2013年4月20日土曜日

baserCMSで会員制のページを作る

最近、baserCMSでホームページを構築しようとしていてそこで調べたことをメモ程度に。
baserCMSを使うとある指定されたページに認証機能をつけることができます。
今回は認証機能を使ってブログ(member_blog)を開こうとしたときに認証をかける例。


まずはファイルのコピーから。
cd basercms
cp ./baser/config/baser.php ./app/config/
cp ./baser/controllers/members_controller.php ./app/controllers/
cp ./baser/models/member.php ./app/models/
cp -r ./baser/views/members ./app/views/


次にコピーした app/config/baser.php を修正します。
// 行101から
$config['BcAuthPrefix'] = array(
    // 管理画面
    'admin' => array(
        (省略)
    ),
    // マイページ(例)
    'mypage' => array(
        'name'           => 'マイページ',
        'alias'          => 'mypage',
        'loginRedirect'  => '/member_blog',
        'loginTitle'     => 'マイページログイン',
        'userModel'      => 'Member',
        'loginAction'    => '/mypage/members/login',
        'toolbar'        => true
    ),
);

とりあえず実装するだけならコメントを外すだけで良いです。
今回は(member_blog)を開いた際に、認証をかけログインできたら(member_blog)を開くようにしたいので loginRedirect の部分だけを書き換えています。
また、ログアウトはまだ実装しないので標準を使用。 toolbar を true にしておきます。

次にbaserCMSにログインしてユーザグループの追加を行います。

注意する点は認証プレフィックス設定でマイページを選択します。
このマイページとは config/baser.php で設定している mypage.name になります。
合わせてこのグループに対応するユーザも作成します。

ひとまずこれで認証機能は完成。
http://localhost/basercms/mypage/members/login
を開くとログイン画面が表示できると思います。

先ほど作成したユーザでログインをするとブログ(member_blog)に自動的にページが遷移します。
動作の確認はこれで良いですが、一度ログアウトして

http://localhost/basercms/member_blog/index
にアクセスしてみてださい。

ブログ(member_blog)が正常に表示されると思いますが、今回はこのブログに制限をかけたいのでもう少し修正が必要です。

修正するファイルはテーマ側。
デフォルトのテーマ(nada-icons)ですと layouts/default.php の先頭に下記を追加します。

$url = $html->url();
$pattern = '/member_blog/';
if (preg_match($pattern, $url)) {
    if (!isset($this->viewVars['user'])) {
        header('Location: '.$bcBaser->getUrl(Configure::read('BcAuthPrefix.mypage.loginAction')));
    }
}


こうすることでブログ(member_blog)配下のアドレスが指定された場合に認証済みかのチェックを行い、認証がまだの場合はログインページに遷移することができます。


こんなかんじでbaserCMSで会員制のページを作ることができました。
まだまだbaserCMSの仕組みがわかっていないので書き方が変なところやこうすれば良いみたいなところがありましたら教えてください。



参考ページ





2013年4月10日水曜日

FuelPHPのチートシートみたいなものを作った

もともとは社内の勉強会ネタで作っていたもの。
http://fuelphpcheatsheet.aws.af.cm/

よく使うものとかを中心に、書いていますがまだまだ情報が少なすぎる状態です。

AppFogを使って見たかったのでそれも兼ねて。
ぼちぼちと更新していきます。



AppFogでの公開については以下のサイトを参考にしました。





2013年1月29日火曜日

似てるけど似てないPHPの配列を結合する

AdventCalendar2012でも書きましたが似てるけど似てないシリーズ。
(シリーズといいながら思いついたときに書き残そうと思っただけですが)
(というかほぼ自分の備忘録)

今回は配列の結合。
最近知ったことなんですが配列を結合に+という配列結合演算子があります。
今まで配列の結合と言えば array_merge と思っていたんですが + もありました。

何か違うことでもあるのかなと思って実際に試してみました。

簡単な例ですが
$tmp1_1 = array("1", "2", "3");
$tmp1_2 = array("a", "b", "c", "d");

var_dump(array_merge($tmp1_1, $tmp1_2));
// 結果
//array
//  0 => string '1' (length=1)
//  1 => string '2' (length=1)
//  2 => string '3' (length=1)
//  3 => string 'a' (length=1)
//  4 => string 'b' (length=1)
//  5 => string 'c' (length=1)
//  6 => string 'd' (length=1)

var_dump($tmp1_1 + $tmp1_2);
// 結果
//array
//  0 => string '1' (length=1)
//  1 => string '2' (length=1)
//  2 => string '3' (length=1)
//  3 => string 'd' (length=1)

全然、違います。
array_merge は指定した配列同士を連結していますが、+ の場合は前に指定した配列に値が追加されるような動きになります。

PHP: array_merge - Manual
http://jp1.php.net/manual/ja/function.array-merge.php
PHP: 配列演算子 - Manual
http://php.net/manual/ja/language.operators.array.php

php.netによると同じキー文字列を有している場合は、後に指定された配列により上書きされる。
とあるので
$tmp2_1 = array(
        "key_1" => "1",
        "key_2" => "2",
        "key_3" => "3",
    );
$tmp2_2 = array(
        "key_1" => "a",
        "key_2" => "b",
        "key_3" => "c",
        "key_4" => "d",
    );

var_dump(array_merge($tmp2_1, $tmp2_2));
// 結果
//array
//  'key_1' => string 'a' (length=1)
//  'key_2' => string 'b' (length=1)
//  'key_3' => string 'c' (length=1)
//  'key_4' => string 'd' (length=1)

var_dump($tmp2_1 + $tmp2_2);
// 結果
//array
//  0 => string '1' (length=1)
//  1 => string '2' (length=1)
//  2 => string '3' (length=1)
//  3 => string 'd' (length=1)

array_merge のほうは同じキー文字列を有しているので上書きされているのがわかります。
+ のほうは先ほどの結果と同じです。

動きを理解しておかないと思わぬ結果が返ってくるかもしれないです。




2013年1月27日日曜日

チートシートアプリ

アプリという方でもないですが。
寝る前に同僚からVimとかSublimeText2のチートシートを作ってと頼まれてたの思い出したので。
適当です。


画面はこんなかんじ。
人それぞれキーバインドしてるから簡単に内容を修正できるようにデータはxmlで。
htmlで作ってるからDropboxとかに置いとけばブラウザで表示できるし、データもxmlだからいつでも修正できる。

とりあえずGithubに置いたからあとはご自由に。
https://github.com/hayashida/cheatsheet






2013年1月20日日曜日

Fieldsetのcheckboxとradioのlabelについて #fuelphp

FuelPHPのFieldsetはFormを自動生成してくれる便利な機能のひとつです。
簡単な登録フォームを作る場合など便利だと思い、私も少し加工したパッケージを作ったことがあります。
Fieldsetの例としては以下がコントローラのソースです。

classes/controller/test.php
<?php

class Controller_Test extends Controller_Template
{
    public function action_index()
    {
        $fieldset = Fieldset::forge();

        $fieldset->add('name', 'Name')
                ->add_rule('required');

        $opt = array(
            '1' => 'Man',
            '2' => 'Woman',
        );
        $fieldset->add('gender', 'Gender',
                array(
                    'options' => $opt,
                    'type' => 'radio', 
                ));

        $opt = array(
            'PHP' => 'PHP',
            'Ruby' => 'Ruby',
            'Python' => 'Python',
        );
        $fieldset->add('lang', 'Lang',
                array(
                    'options' => $opt,
                    'type' => 'checkbox',
                ));

        $this->template->content = View::forge('test/index');
        $this->template->content->set_safe('form', $fieldset->build());
    }
}


これでView側(ここではview/test/index.php)は以下を記述するだけで登録フォームを生成してくれます。
<?php
    echo $form;

便利です。
populateやrepopulateを使うことでバリデーション後やモデルからデータを反映など実装してくれるので良いのですが、checkboxとradioを使った場合、現行バージョン(2013/01/19現在、1.4)ではソースを見ると以下のようになっています。
(langのcheckboxだけを抜粋)
<tr>
    <td class=""><label for="form_">Lang</label></td>
    <td class="">
        <input type="checkbox" id="form_lang_0" name="lang[0]" value="PHP" /> <label for="form_form_lang_0">PHP</label><br />
        <input type="checkbox" id="form_lang_1" name="lang[1]" value="Ruby" /> <label for="form_form_lang_1">Ruby</label><br />
        <input type="checkbox" id="form_lang_2" name="lang[2]" value="Python" /> <label for="form_form_lang_2">Python</label><br />
        <span></span>            
    </td>
<;/tr>

checkboxに紐づくはずのlabelのforが「form_form_xxx」となっています。
見た目は特に問題ですが、labelとcheckboxと紐付かないのはなかなか頂けません。
coreのプログラムを追ってたんですが、助言を頂いて1.5-devなら・・・ということで試してみました。

以下は1.5-devで実装した結果
<tr>
 <td class=""><label for="form_">Lang</label></td>
 <td class="">
  <input type="checkbox" id="form_lang_0" name="lang[0]" value="PHP" /> <label for="form_lang_0">PHP</label><br />
  <input type="checkbox" id="form_lang_1" name="lang[1]" value="Ruby" /> <label for="form_lang_1">Ruby</label><br />
  <input type="checkbox" id="form_lang_2" name="lang[2]" value="Python" /> <label for="form_lang_2">Python</label><br />
  <span></span>   
 </td>
</tr>

とりあえずはOK。確かになおってます。
今すぐどうにかしたい方はCoreの部分でdiffするとかやってみるといいかもしれませんね。




2013年1月9日水曜日

Sublime Text2の設定メモ

いろんなサイトを参考にしながら自分なり設定したことをメモ程度に。

ダウンロード
Sublime Text: The text editor you'll fall in love with

参考にしたサイトの紹介

この3つを見てもらえれば大抵の設定はできるので特に書く事もありませんが、自分の設定関係やらキーバインドやらをダラダラと。。。

Preferences - Settings User
{
 // フォントの設定
 "font_face": "Ricty",
 "font_size": 12.0,
 // 現在の行をハイライト
 "highlight_line": true,
 // Vimの有効化
 "ignored_packages":
 [
 ],
 "vintage_ctrl_keys": true,
 "vintage_start_in_command_mode": true,
 // ルーラの表示
 "rulers":
 [
  80,
  120
 ],
 // タブサイズ
 "tab_size": 4,
 // タブをスペースに変換
 "translate_tabs_to_spaces": true
}

Preferences - Key Bindings User
[
    // モードの切替を行わずに改行
    {
        "keys": ["ctrl+o"], "command": "run_macro_file",
        "args": {"file": "Packages/Default/Add Line.sublime-macro"}
    },
    {
        "keys": ["ctrl+O"], "command": "run_macro_file",
        "args": {"file": "Packages/Default/Add Line Before.sublime-macro"}
    },
    // INSERT MODEから抜ける
    {
        "keys": ["j", "j"], "command": "exit_insert_mode",
        "context":
        [
            { "key": "setting.is_widget", "operand": false },
            { "key": "setting.command_mode", "operand": false }
        ]
    },
    // タブ切替
    { "keys": ["ctrl+tab"], "command": "next_view" },
    { "keys": ["ctrl+shift+tab"], "command": "prev_view" },
    {
        "keys": ["g", "t"], "command": "next_view",
        "context":
        [
            { "key": "setting.is_widget", "operand": false },
            { "key": "setting.command_mode" }
        ]
    },
    {
        "keys": [ "G", "T" ], "command": "prev_view",
        "context":
        [
            { "key": "setting.is_widget", "operand": false },
            { "key": "setting.command_mode" }
        ]
    },
    // Command Modeでのカーソル移動
    {
        "keys": ["0"], "command": "move_to", "args": { "to": "bol", "extend": false },
        "context":
        [
            { "key": "setting.is_widget", "operand": false },
            { "key": "setting.command_mode" }
        ]
    },
    {
        "keys": ["9"], "command": "move_to", "args": { "to": "eol", "extend": false },
        "context":
        [
            { "key": "setting.is_widget", "operand": false },
            { "key": "setting.command_mode" }
        ]
    },
    // INSERT MODEでのカーソル移動
    {
        "keys": ["ctrl+h"], "command": "set_motion",
        "args": { "motion": "vi_move_by_characters_in_line", "motion_args": { "forward": false, "extend": true }},
        "context":
        [
            { "key": "setting.command_mode", "operand": false },
            { "key": "setting.is_widget", "operand": false }
        ]
    },
    {
        "keys": ["ctrl+l"], "command": "set_motion",
        "args": { "motion": "vi_move_by_characters_in_line", "motion_args": { "forward": true, "extend": true }},
        "context":
        [
            { "key": "setting.command_mode", "operand": false },
            { "key": "setting.is_widget", "operand": false }
        ]
    },
    {
        "keys": ["ctrl+k"], "command": "set_motion",
        "args": { "motion": "move", "motion_args": { "by": "lines", "forward": false, "extend": true }},
        "context":
        [
            { "key": "setting.command_mode", "operand": false },
            { "key": "setting.is_widget", "operand": false }
        ]
    },
    {
        "keys": ["ctrl+j"], "command": "set_motion",
        "args": { "motion": "move", "motion_args": { "by": "lines", "forward": true, "extend": true }},
        "context":
        [
            { "key": "setting.command_mode", "operand": false },
            { "key": "setting.is_widget", "operand": false }
        ]
    }
]

今のところインストールしているパッケージは

  • SideBarEnhancements ・・・サイドバーの拡張
  • Emmet ・・・Zencodingの次期バージョン?進化版?
  • SublimeLinter ・・・リアルタイムで文法チェック
  • Additional PHP Snippets ・・・PHP用のスニペット
  • SCSS ・・・Sass、Scssのシンタックス
  • ConvertToUTF8 ・・・Shift_JISに対応させるプラグイン


とこんなかんじです。
まだ使いこなせて感、満載ですがとりあえずVimっぽい動きとPHPを書く準備はできました。




2012年12月18日火曜日

似てるけど似てないシリーズ #phpadvent2012

この記事はPHP Advent Calendar 2012の18日目です。
昨日はkiou oubaさんのフレームワークとは一体何だったのかでした。

私はオレオレFWとまではいきませんがずっと素書きでPHPを書いてきてましたが、今年からフレームワークも使ってみようと思ってFuelPHP、CakePHPとFWの勉強をしていました。
そこで勉強になったことやFWの良いところFWによる違い何かを書こうと意気込んでたんですが業務に追われてしまい、何も準備できずに今日になってしまいました。
Advent Calendarの流れ的にもよかったのかなと思って後悔してます。
来年またチャンスがあれば書けるように頑張ります!


準備してたネタとは違いますが、PHPの初歩的な部分を書いてみました。
7日目にはじかみさんがIntegerの上限を超えてゆけでも書かれてましたが、PHP.net。PHPのマニュアル的なサイトですがたまにはこれ見て勉強するのもいいですよね。
私も夏ごろにこのスライド見てPHP.netいろいろ見てみました。
https://t.co/e4nGnfAe
これはFukuoka.PHPという福岡でやってるPHPの勉強会で@akase244さんが発表されたスライドです。とても面白いスライドなので是非これも見て下さい!!

私が調べてみたのはPHPには似てるけど動きは全く別物だったり、似てるけど・・やっぱり一緒、みたいな関数。

PHP.netにも関数エイリアスというページがあって is_int()is_integer() の例のように is_integer() のページには「is_int()のエイリアス」とだけ書かれてます。
http://php.net/manual/ja/aliases.php

どっちがいいのかはわかりませんが、基本的にここに書いてあるのは同じ動作をします。

しかし、前述したように似てるけど全く別物というのもあります。
初心にもどった気分で読んでもらえれば嬉しいです。


まず

echo と print の違い


同じ文字列を出力する関数(ドキュメントには関数ではないと書かれてますが)
PHP始めたころはどっちで書けばいいんだろうとか気になってたこともあります。
<?php
    echo 'Hello, World!";
    print 'Hello, World!';
?>
出力される結果に違いはありませんが、echo では複数の文字列をカンマ区切りで記述することができます。
<?php
    echo 'Hello', 'World';    // OK
    print 'Hello', 'World';   // NG
?>
また、echo では返り値がないのに対し print は返り値で常に1を返します。
echo の方が返り値がない分、早いらしいです。
これだけ見ると echo のほうが良いのかなって思います。
けっこうどのサンプルも echo で書かれたりしてるのでやっぱり echo なのかな。


2つ目に

print_r と var_dump の違い


変数の値を確認したい場合に使う関数(何かとお世話になってます)
<?php
    $a = array(1, "2", true, array("a", "b"));

    print_r($a);
    var_dump($a);
?>

これは出力結果がかなり違ってます。
print_r の場合
Array
(
    [0] => 1
    [1] => 2
    [2] => 1
    [3] => Array
        (
            [0] => a
            [1] => b
        )

)

var_dump の場合
array
  0 => int 1
  1 => string '2' (length=1)
  2 => boolean true
  3 =>
    array
      0 => string 'a' (length=1)
      1 => string 'b' (length=1)

print_r では内容をただ出力している感がありますが、var_dump では型まで出力してくれます。
PHPでは明示的な型指定がない分、条件式とかでハマることが多々あるので個人的には var_dump のほうが好きです。
ちなみに var_dump のほうは変数を複数指定して出力することができます。
<?php
    var_dump($a, $b);
?>


3つ目に

シングルクォーテーションとダブルクォーテーションの違い


関数ではありませんが変数に文字列を格納する場合、どちらで囲むか。
一般的に使い分けをしているのかどうかわかりませんがこれも違うもので
<?php
    $name = 'Hayashida';

    $single = '私は $name です。';
    $double = "私は $name です。";

    echo $single;
    echo $double;
?>

出力結果は
シングルクォーテーションの場合
私は $name です。
ダブルクォーテーションの場合
私は Hayashida です。

シングルクォーテーションはそのまま出力するのに対し、ダブルクォーテーションは変数を展開してくれます。
上記の例では半角スペースをいれてますが、{ } で囲むことで確実に変数と認識させることができます。
ということはこんなこともできる。
<?php
    $closure = function($val) {
        return str_replace('a', '@', $val);
    };

    echo "私は {$closure($name)} です。";
?>

出力結果は
私は H@y@shid@ です。

文字列の変数に置換する場合などは sprintf とか使うことが多いと思いますが
知っておくと便利かもしれません。


4つ目に

and と && の違い


元々VBをやってたおかげ?で、PHPを始めたころハマったことあります。
条件式などを書く場合ですが、PHPの演算子には優先順位があってそれを知らないと意外なところでバグがでるかも。
http://php.net/manual/ja/language.operators.precedence.php
<?php
    $x = true and false;
    $y = true && false;

    var_dump($x, $y);
?>
二つの評価値(true or false)を比較して変数に代入。
なんてことをする場合、上記のように書くと結果が違います。というか意味が違います。

結果は
boolean (true)
boolean (false)

$x がなぜ true ??
理由はマニュアルに書いていますが、なぜかというと and より = のほうが優先度が高いからです。
$x の場合、$x という変数に true を代入し、その結果を and false としても意味がないものになってしまいます。
and と使う場合は $x = (true and false) とするのが正。
$y のほうは、 && のほうが = より優先度が高いからこのままでも良いのです。

or と || も同じようなことが言えます。


まとめ

取り留めも無い記事になってしまいましたが、今年は勉強会にも参加させてもらったりしてフレームワークやらPSRやらいろいろ勉強になりました。
来年はもう少しましな記事をかけるように頑張ろう。



明日はTakayuki Miwaさんです。よろしくお願いします。