開発メモ,主に補足by子連れ親父プログラマー

2011-09-16

CakePHP1.3で作る会員管理システム(15) メール送信

メール送信

ここで会員登録時のメール送信を作ります。 Emailコンポーネントの使い方は本家サイトのドキュメントの通りです。

/app 直下の app_controller.php を開いて、

class AppController extends Controller {
}
となっている中に、
    var $components = array('Session', 'Email');
と入れます。

そして、以下のようなファンクションを入れます。

function _sendEmail($template, $subject, $to, $attachments, $from, $replyto, $fromName, $sendAs, $bcc) {
    if (!$from) {$from = 'your@email';}
    if (!$replyto) {$replyto = 'your@email';}
    if ($fromName) {$from = $fromName . " <$from>";}
    $this->Email->to = $to;
    $this->Email->bcc = $bcc;
    $this->Email->subject = $subject;
    $this->Email->replyTo = $replyto;
    $this->Email->from = $from;
    $this->Email->template = $template;
    if ($attachments) {$this->Email->attachments = $attachments;}
    $this->Email->sendAs = $sendAs;
    $this->Email->send();
}

smtp で送信する場合は、$this->Email->send() の部分を以下に書き換えます。

        $this->Email->smtpOptions = array(
            'port'=>'587',
            'timeout'=>'30',
            'host' => 'your.host.name',
            'username'=>'username',
            'password'=>'password'
        );
        $this->Email->delivery = 'smtp';
        $this->Email->send();
        $this->set('smtp-errors', $this->Email->smtpError);

gmailで送る場合は、smtpOptions のところを以下のようにします。

        $this->Email->smtpOptions = array(
            'port'=>'465',
            'timeout'=>'30',
            'host' => 'ssl://smtp.gmail.com',
            'username'=>'your@email',
            'password'=>'yourpassword'
        );

メールの文字コードは、デフォルトだとUTF-8で送られます。 charsetは以下で設定できますが、ISO-2022-JP にすると subject が文字化けするようです。

$this->Email->charset = "ISO-2022-JP";

from のメールアドレスは固定だし、text形式のメールしか送らない、というのであれば、 最初に設定した app_controller.php で、

    var $components = array(
        'Session', 
        'Email' => array(
            'from' => 'your@email',
            'sendAs' => 'text',
        ),
    );
というように書くこともできます。

こうすると、function _sendEmail() の中では指定する必要がありません。

//        $this->Email->sendAs = $sendAs;

つまり、var $components の方にどんどん指定していってしまうと、function _sendEmail() の方に書くことがなくなり、どんどん減っていきます。
自分の使いやすいと思うあたりに調節すればよいと思います。

メール文面のテンプレートは、まずレイアウトを

  • /app/views/layouts/email/html/default.ctp
  • /app/views/layouts/email/text/default.ctp
に入れます。

テキストメールの場合は、とりあえず、default.ctp に

<?php echo $content_for_layout; ?>
とだけ書いて保存します。

文面は

  • /app/elements/email/html/default.ctp
  • /app/elements/email/text/default.ctp
に入れます。

文面は普通に、確認画面の view.ctp と同じように作ればいいと思います。

以下の会員登録がありました。
-----------------------------------------------------
メールアドレス: <?php echo $member['Member']['email'] ."\n"; ?>
会員種別:<?php echo $types[$member['Member']['type_id']] ."\n"; ?>
誕生日:<?php echo $member['Member']['birthday']['year']; ?>年<?php echo $member['Member']['birthday']['month']; ?>月<?php echo $member['Member']['birthday']['day']; ?>日
好きな物:
<?php
if (!empty($member['Favorite'])) {
    foreach ($member['Favorite']['Favorite'] as $favorite) {
        echo "\t".$favorites[$favorite['id']]."\n";
    }
}
?>

こんな感じです。
こちらの elements の中の方のファイル名を上記 $this->Email->template に指定します。

ここではとりあえず、

/app/elements/email/text/member_add.ctp
としました。

で、コントローラ members_cntroller.php のアクション add のsaveしてる部分の下に

            } else {
                $this->Member->create();
                if ($this->Member->save($this->data)) {
                    $this->set('member', $this->data);
                    $attachments = array();
                    $this->_sendEmail('member_add', 'ユーザー登録のお知らせ', 'your@email', $attachments,'','','','text',array());
                    $this->Session->setFlash(__('The member has been saved', true));
                    $this->redirect(array('action' => 'complete'));
                } else {
                    $this->Session->setFlash(__('The member could not be saved. Please, try again.', true));
                }
            }
を入れます。
メールを受信して確認します。

CakePHP1.3で作る会員管理システム(14) checkbox の validate

checkbox の validate

動作がおかしい「好きな物」のチェックボックスを直していきます。

「好きな物」は Favorite モデルですが、あくまでここでは Member を登録している訳ですから Member モデルとして処理します。
今 add.ctp でこうなってる部分を、

        echo $this->Form->input('Favorite', array('multiple'=>'checkbox', 'label' => '好きな物'));
こうします。

        echo $this->Form->input('favorites', array('multiple'=>'checkbox', 'label' => '好きな物'));

するとなんと!

<input type="checkbox" id="MemberFavorites1" value="1" name="data[Member][favorites][]">

こういうソースが生成されます。
これはモデル Member です。

ということで Member モデルの方にルールを書きます。
/app/models/member.php の $validate が書かれている部分の 'birthday' の下に以下を追加します。

        'favorites'=>array(
            'custom' => array(
                'rule'=>array('multiple', array('min' => 1, 'max' => 3)),
                'message' => '好きな物は一つ以上選択してください'
            ),
        ),

次にコントローラに移動して、確認画面の時に validate するように members_controller.php を書き換えます。

if (!empty($this->data)) {
から始まる if 文の最初に、
$this->data['Favorite']['Favorite'] = $this->data['Member']['favorites'];
を入れます。

これで favorites を本来の Favorite に入れ直しています。 で、

if ($this->data['Member']['mode'] == 'confirm') {
から始まる mode="confirm" の部分の if 文を以下のように変えます。

if ($this->data['Member']['mode'] == 'confirm') {
    $this->Member->set($this->data);
    if ($this->Member->validates($this->data)) {
        $this->set('member', $this->data);
        $this->render('confirm');
    } else {
        $this->Session->setFlash(__('エラーがあります', true));
    }
} elseif ($this->data['Member']['mode'] == 'back') {//

これで正しくエラーチェックが動くようになりました。

あとまだ、好きな物チェックボックスの確認画面がおかしいので、
今 confirm.ctp の

    echo $this->Form->input('Favorite', array('type'=>'hidden'));
こうなっているところを、
    foreach ($member['Member']['favorites'] as $k => $v){
        echo $this->Form->input("Member.favorites.$k", array('type'=>'hidden'));
    }
このようにします。

これで生成されるHTMLの hidden の部分が、

<input id="MemberFavorites0" type="hidden" value="1" name="data[Member][favorites][0]">
<input id="MemberFavorites1" type="hidden" value="3" name="data[Member][favorites][1]">
のように出力されるようになります。

戻るボタンクリックでも値が保持されています。
今まで保存されていなかった members_favorites テーブル にもデータが保存されています。

CakePHP1.3で作る会員管理システム(13) checkbox、 戻るボタン、年月セレクト、完了画面

checkbox、 戻るボタン、年月セレクト、完了画面

次に、add.ctp 入力フォームの、Favorite(好きな物)が multiple セレクトになってるのを直します。
日本では複数選択にセレクトなんてほとんど使われないですよね。
こうなっているのを、

        echo $this->Form->input('Favorite');
こうします。

        echo $this->Form->input('Favorite', array('multiple'=>'checkbox', 'label' => '好きな物'));

これでとりあえずチェックボックスになるんですが、
どうも一つのチェックで一行になっているので収まりが悪いです。
横に並べたいですね。
生成されたHTMLを確認すると、以下のようになっています。

<div class="input select">
    <label for="FavoriteFavorite">好きな物</label>
    <input type="hidden" id="FavoriteFavorite" value="" name="data[Favorite][Favorite]">
    <div class="checkbox">
        <input type="checkbox" id="FavoriteFavorite1" value="1" name="data[Favorite][Favorite][]">
        <label for="FavoriteFavorite1">apple</label>
    </div>
    <div class="checkbox">
        <input type="checkbox" id="FavoriteFavorite2" value="2" name="data[Favorite][Favorite][]">
        <label for="FavoriteFavorite2">orange</label>
    </div>
    <div class="checkbox">
        <input type="checkbox" id="FavoriteFavorite3" value="3" name="data[Favorite][Favorite][]">
        <label for="FavoriteFavorite3">grape</label>
    </div>
</div>

チェックボックス一つにつき一つの div で囲まれています。
css を書くのもしんどいので、jQuery で処理することにします。
jQuery をダウロードして解凍しておいてください。

/app/webroot/js 以下に jquery.js としてコピーしておきます。
で、さらに /app/webroot/js 以下に、新規に util.js という名前でファイルを作ります。

中身は、こんな感じで。

$(document).ready(function() {
    $('div.checkbox').css('display','inline');
    $(':checkbox').css('float','none');
});

周りを囲んでいる div を inline 表示に変えて、左に float しているチェックボックスの float を解除しているだけです。

で、 add.ctp の一番上に、

<?php echo $javascript->link(array('jquery','util'), false); ?>
を追加します。

さらに、members_controller.php の 上の方に $helpers を追加します。

<?php
class MembersController extends AppController {

    var $name = 'Members';
    var $helpers = array('Javascript');

    function index() {
        $this->Member->recursive = 0;
        $this->set('members', $this->paginate());
    }

ブラウザで確認してみると、チェックボックスが横に並んでいます。
これはあくまでその場しのぎの付け焼刃ですので、本来はきちんとデザイナーさんに css を書いてもらいましょう。

ついでなので、さきほどのJavascriptの util.js の $(document).ready(function() {});の中に、以下を追加しておきます。

    $('#back').click(function(){
        $('#MemberMode').val('back');
        $("#MemberConfirm").submit();
    });

解説:
1行目:id="back" のボタンをクリックしたら
2行目:id="MemberMode" の valueを "back" にして(hidden で追加した mode の value です)
3行目:id="MemberConfirm" のフォームをサブミットする(確認画面の form です)

confirm.ctp の一行目に以下を追加します。

<?php echo $javascript->link(array('jquery','util'), false); ?>

members_controller.php の前回追加した if ~ else の中に以下の elseif を追加します。{} の中は空でいいです。

            if ($this->data['Member']['mode'] == 'confirm') {
                //・・・
            } elseif ($this->data['Member']['mode'] == 'back') {

            } else {
                //・・・
            }

これで、確認画面から入力画面への「戻る」ボタンが動くようになります。
いろいろエラーが出ているかもしれませんが、たいした問題ではないので気にしないで進みます。

あとは、誕生日の入力フォームが洋風で気に入らないので、変更します。

今こうなってるのを、

        echo $form->input('birthday');
以下に変更します。

        echo $this->Form->input('birthday',array('dateFormat'=>'YMD','maxYear'=>date('Y'),'minYear'=>date('Y')-100,'monthNames'=>false, 'label' => array('text'=>'誕生日')));

最後、一応公開側は完了画面を出すことにするので、「登録されました」みたいな適当なビューを complete.ctp という名前で作っておきます。

<div class="members form">
    <h2><?php __('会員登録'); ?></h2>

    <p>登録されました。</p>
</div>

そして、members_controller.php の add アクションの save の後の、

                    $this->redirect(array('action' => 'index'));
となっているのを、
                    $this->redirect(array('action' => 'complete'));
に変更し、さらに、
function complete() {
}
を追加しておきます。
ブラウザで完了画面が表示されることを確認します。

2011-09-15

CakePHP1.3で作る会員管理システム(12) 確認画面その2

確認画面その2

ではビューについて、順番に整理していきます。

confirm.ctp から管理メニュー部分

<div class="actions">
....
</div>
で囲まれたところをざくっと削除します。いらないので。

Birthday(誕生日)のところ、

<?php echo $member['Member']['birthday']; ?>
こうなっているのを、以下に変更します。

<?php echo $member['Member']['birthday']['year'] .'/' . $member['Member']['birthday']['month'] .'/'. $member['Member']['birthday']['day']; ?>

同じく “hidden” の Birthday 部分、

echo $this->Form->input('birthday', array('type'=>'hidden'));
これを以下に変更します。

echo $this->Form->input('birthday.year', array('type'=>'hidden'));
echo $this->Form->input('birthday.month', array('type'=>'hidden'));
echo $this->Form->input('birthday.day', array('type'=>'hidden'));

Type(会員種別) のところ、

<?php echo $this->Html->link($member['Type']['name'], array('controller' => 'types', 'action' => 'view', $member['Type']['id'])); ?>
こうなっているのを、以下に変更します。

<?php echo $types[$member['Member']['type_id']]; ?>

次に「好きな物」に関して、

<div class="related">
....
</div>
ではさまれたの関連テーブル部分をごっそり削除し、その代わりにメインのテーブルの Img2 の表示部分(tr で囲まれた一角)の下に以下を追加します。

  <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('好きな物'); ?></dt>
  <dd<?php if ($i++ % 2 == 0) echo $class;?>>
   <?php if (!empty($member['Favorite']['Favorite'])):?>
   <ul>
    <?php foreach ($member['Favorite']['Favorite'] as $favorite): ?>
     <li><?php echo $favorites[$favorite['id']];?></li>
    <?php endforeach; ?>
   </ul>
   <?php endif; ?>
    
  </dd>

members_controller.php に戻って、 function add() の、一番下の

  $types = $this->Member->Type->find('list');
  $favorites = $this->Member->Favorite->find('list');
  $this->set(compact('types', 'favorites'));
3行を、一番上に持ってきます。

こうなります。

 function add() {
  $types = $this->Member->Type->find('list');
  $favorites = $this->Member->Favorite->find('list');
  $this->set(compact('types', 'favorites'));
  
  if (!empty($this->data)) {
   if ($this->data['Member']['mode'] == 'confirm') {
    $this->Member->set($this->data);

ブラウザで確認します。
ここまでで、Type(会員種別)、Birthday(誕生日)、好きな物 が表示されるようになったはずです。
ボタン「送信」をクリックで、一覧画面に戻り、

The Member has been saved
と表示されればOKです。membersテーブルのデータは保存されています。

2011-09-14

CakePHP1.3で作る会員管理システム(11) 確認画面その1

確認画面その1

まず、確認画面のビューを作ります。 bake で自動生成した、 view.ctp がそのまま使えそうなので、 view.ctp を開いてから「名前を付けて保存」で confirm.ctp を作成します。

今回確認画面はhidden方式でいくので、

<div class="members view">
となっている所の、直下にフォームを作ります。

<?php echo $this->Form->create('Member', array('id'=>'MemberConfirm')); ?>

こんな感じです。 ただの

$this->Form->create('Member');
だけでもいいっちゃいいんですが、そうすると、以下のような add の画面と全く同じ id でフォームタグが生成されてしまうので、
<form id="MemberAddForm" accept-charset="utf-8" method="post" action="/~myname/cake/members/add">
これはなんとなく気持ち悪いので、
array('id'=>'MemberConfirm')
を指定して、確認画面用のフォームの id を指定しておきます。

で、その下に add.ctp のフォーム部分、

<?php
    echo $this->Form->input('email');
    echo $this->Form->input('password');
    echo $this->Form->input('type_id');
    echo $this->Form->input('birthday');
    echo $this->Form->input('img1');
    echo $this->Form->input('img2');
    echo $this->Form->input('Favorite');
?>
をごっそりそのままコピーして貼り付けます。

hidden にするので

array('type'=>'hidden')
を一個一個全部に指定して、一応全体を div で囲んでおきます。 こんな感じになりました。

<div class="members view">
<?php echo $this->Form->create('Member', array('id'=>'MemberConfirm'));?>
<div style="display:none;">
<?php
    echo $this->Form->input('email', array('type'=>'hidden'));
    echo $this->Form->input('password', array('type'=>'hidden'));
    echo $this->Form->input('type_id', array('type'=>'hidden'));
    echo $this->Form->input('birthday', array('type'=>'hidden'));
    echo $this->Form->input('img1', array('type'=>'hidden'));
    echo $this->Form->input('img2', array('type'=>'hidden'));
    echo $this->Form->input('Favorite', array('type'=>'hidden'));
?>
</div>

<h2><?php  __('Member');?></h2>

ただ、アクションとしては同じ add で処理するので、なにかで識別するようにしないと「今は確認画面だ!」というのが分かりません。

ということで、 mode = ‘confirm’ というのを作り出して、これを add.ctp (フォーム入力画面)の方に、 hidden で入れておきます。

add.ctp 側

<div class="members form">
<?php echo $this->Form->create('Member');?>
<div style="display:none;">
    <?php echo $this->Form->hidden('mode', array('value'=>'confirm')); ?>
</div>

    <h2>
        <?php __('Add Member'); ?></h2>

confirm.ctp 側はvalueなしで。以下を追加。

    echo $this->Form->input('mode', array('type'=>'hidden','value'=>''));

これで、

  • add → confirm へは mode = ‘confirm’ で、
  • confirm → complete へは mode = ” で
行く事になります。 最後に、ボタンを追加しておきます。

<div class="submit">
    <?php echo $this->Form->button('戻る', array('id'=>'back')); ?>
</div>
<?php echo $this->Form->end('送信'); ?>

これはどっか適当に下の方に入れておきます。 一応ただの id=”back” ボタンをつけておきます。

あと、view.ctp との違いで、そっちには id がありますが、こっちにはまだ id は決まっていない、存在していないので、以下の id に関する表示部分を削除しておきます。

        <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Id'); ?></dt>
        <dd<?php if ($i++ % 2 == 0) echo $class;?>>
            <?php echo $member['Member']['id']; ?>
             
        </dd>

同様に、 Created と Modified も要らないので削除しておきます。

        <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Created'); ?></dt>
        <dd<?php if ($i++ % 2 == 0) echo $class;?>>
            <?php echo $member['Member']['created']; ?>
             
        </dd>
        <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Modified'); ?></dt>
        <dd<?php if ($i++ % 2 == 0) echo $class;?>>
            <?php echo $member['Member']['modified']; ?>
             
        </dd>

ここでもうそろそろ画面を見たいのでコントローラをいじります。

/app/controllers/members_controller.php を開いて、function add() の以下の部分、

        if (!empty($this->data)) {
            $this->Member->create();
            if ($this->Member->save($this->data)) {
                $this->Session->setFlash(__('The member has been saved', true));
                $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The member could not be saved. Please, try again.', true));
            }
        }
この1行目からのif文の中にさらにもう一個if文を入れて、もとからあった部分はelseのあとにつっこみます。

構造としてはこんな感じ。

if (!empty($this->data)) {
    if () {
     
    } else {
    // もとからあった部分
    }
}

で、その新しいif文を以下のようにします。

    function add() {
        if (!empty($this->data)) {
            if ($this->data['Member']['mode'] == 'confirm') {
                $this->Member->set($this->data);
                $this->set('member', $this->data);
                $this->render('confirm');
            } else {
                $this->Member->create();
                if ($this->Member->save($this->data)) {
                    $this->Session->setFlash(__('The member has been saved', true));
                    $this->redirect(array('action' => 'index'));
                } else {
                    $this->Session->setFlash(__('The member could not be saved. Please, try again.', true));
                }
            }
        }

これで確認画面が出るはずなのでブラウザで /members/add を開いて適当に入力して進むと・・・
ぼこぼこにエラーが出てますが、入力したEmailの値とかは表示されてるはずです。
エラーは配列とかの問題だけなので今は気にしなくていいです。

2011-09-13

CakePHP1.3で作る会員管理システム(10) レイアウトその2

レイアウトその2

続いて、一般の人が登録したり、ログインして編集する画面(公開側)のレイアウトを作ります。 通常公開側はデザイナーさんがカッチリデザインしてくるものですから、どっちみち最終的にそのデザインに合わせて調整することになると思います。 ということで、ここでは admin 側をそのまま流用してファイルだけ作っておくことにします。

まず、先ほど作った

/app/views/layouts/admin.ctp
をそのまま同じ場所にコピーして、member.ctp にリネームします。
/app/views/layouts/member.ctp

そして左メニューの部分を以下のように編集します。

            <div class="actions">
                <h3><?php __('メニュー'); ?></h3>
                <ul>
                    <li><?php echo $this->Html->link(__('登録情報変更', true), array('controller'=>'members','action' => 'edit'));?></li>
                    <li><?php echo $this->Html->link(__('退会', true), array('controller' => 'members', 'action' => 'delete')); ?> </li>
                    <li><?php echo $this->Html->link(__('ログアウト', true), array('controller' => 'users', 'action' => 'logout')); ?> </li>
                </ul>
            </div>

member.ctp のヘッダー部の以下の部分、

<head>
    <?php echo $this->Html->charset(); ?>
    <title>
        <?php echo $title_for_layout; ?>
    </title>
    <?php
        echo $this->Html->meta('icon');

        echo $this->Html->css('cake.generic');

        echo $scripts_for_layout;
    ?>
</head>
cssを指定しているところを以下のように書き換えます。

        echo $this->Html->css('member');

これで出力されるソースは

<link href="/~myname/cake/css/member.css" type="text/css" rel="stylesheet">
となります。

css の置き場所は /app/webroot/css/ ですので、

/app/webroot/css/cake.generic.css
をそのまま同じ場所にコピーして、member.css にリネームします。

/app/webroot/css/memmber.css

最後に、admin の場合と、member の場合で、自動でレイアウトが切り替わるように設定します。

まず、前回 member_controller.php に入れた、

    function beforeFilter() {
        $this->layout = 'admin';
    }
を削除しておきます。

そして、/app 直下に app_controller.php を配置します。

cd Sites/cake
cp cake/libs/controller/app_controller.php app/

今コピーした、/app/app_controller.php に以下を追加します。

<?php
/**
 * Application level Controller
 *
 * This file is application-wide controller file. You can put all
 * application-wide controller-related methods here.
 *
 * PHP versions 4 and 5
 *
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
 * @link          http://cakephp.org CakePHP(tm) Project
 * @package       cake
 * @subpackage    cake.cake.libs.controller
 * @since         CakePHP(tm) v 0.2.9
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 */

/**
 * This is a placeholder class.
 * Create the same file in app/app_controller.php
 *
 * Add your application-wide methods in the class below, your controllers
 * will inherit them.
 *
 * @package       cake
 * @subpackage    cake.cake.libs.controller
 * @link http://book.cakephp.org/view/957/The-App-Controller
 */
class AppController extends Controller {

    function beforeFilter(){
        if (!empty($this->params['admin'])) {
            $this->layout = "admin";
        }else{
            $this->layout = "member";
        }
    }

}

これで admin の時と admin でない時でレイアウトが切り替わります。

2011-09-11

CakePHP1.3で作る会員管理システム(9) レイアウトその1

レイアウトその1

で、ついでなので管理画面っぽく、レフトメニューがあって作業を選べるようなページレイアウトに変更します。

/cake/libs/view/layouts/default.ctp がもともとのレイアウトファイルなので、これを開いて参考にしながら、自分の admin 用のレイアウト admin.ctp を作ります。 それは /app/views/layouts に保存します。

/app/views/layouts/admin.ctp

今まで add.ctp などをいじってきて気がついていると思いますが、フォームなどのメイン部分の下に、左メニュー部分が Actions として入っています。

つまり全体としては、こんな構造になっていて、

<div id="header"></div>
<div id="content">
    <div class="members form"></div>
    <div class="actions"></div>
</div>

各ページのテンプレート($content_for_layout の中に入る部分)が、
    <div class="members form"></div>
    <div class="actions"></div>
になっている、という訳です。

ということで、このactionsを分離して、レイアウトの方に入れてしまいます。

add.ctp から

<div class="actions">
 <h3><?php __('Actions'); ?></h3>
 <ul>

  <li><?php echo $this->Html->link(__('List Members', true), array('action' => 'index'));?></li>
  <li><?php echo $this->Html->link(__('List Types', true), array('controller' => 'types', 'action' => 'index')); ?> </li>
  <li><?php echo $this->Html->link(__('New Type', true), array('controller' => 'types', 'action' => 'add')); ?> </li>
  <li><?php echo $this->Html->link(__('List Favorites', true), array('controller' => 'favorites', 'action' => 'index')); ?> </li>
  <li><?php echo $this->Html->link(__('New Favorite', true), array('controller' => 'favorites', 'action' => 'add')); ?> </li>
 </ul>
</div>
この部分をカットし、admin.ctp (もともとはdefault.ctp)の $content_for_layout の下ににコピーします。

<?php
/**
 *
 * PHP versions 4 and 5
 *
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
 * @link          http://cakephp.org CakePHP(tm) Project
 * @package       cake
 * @subpackage    cake.cake.libs.view.templates.layouts
 * @since         CakePHP(tm) v 0.10.0.1076
 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
 */
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <?php echo $this->Html->charset(); ?>
 <title>
  <?php __('CakePHP: the rapid development php framework:'); ?>
  <?php echo $title_for_layout; ?>
 </title>
 <?php
  echo $this->Html->meta('icon');

  echo $this->Html->css('cake.generic');

  echo $scripts_for_layout;
 ?>
</head>
<body>
 <div id="container">
  <div id="header">
   <h1><?php echo $this->Html->link(__('CakePHP: the rapid development php framework', true), 'http://cakephp.org'); ?></h1>
  </div>
  <div id="content">

   <?php echo $this->Session->flash(); ?>

   <?php echo $content_for_layout; ?>

   <div class="actions">
    <h3><?php __('Actions'); ?></h3>
    <ul>
     <li><?php echo $this->Html->link(__('List Members', true), array('action' => 'index'));?></li>
     <li><?php echo $this->Html->link(__('List Types', true), array('controller' => 'types', 'action' => 'index')); ?> </li>
     <li><?php echo $this->Html->link(__('New Type', true), array('controller' => 'types', 'action' => 'add')); ?> </li>
     <li><?php echo $this->Html->link(__('List Favorites', true), array('controller' => 'favorites', 'action' => 'index')); ?> </li>
     <li><?php echo $this->Html->link(__('New Favorite', true), array('controller' => 'favorites', 'action' => 'add')); ?> </li>
    </ul>
   </div>
  </div>
  <div id="footer">
   <?php echo $this->Html->link(
     $this->Html->image('cake.power.gif', array('alt'=> __('CakePHP: the rapid development php framework', true), 'border' => '0')),
     'http://www.cakephp.org/',
     array('target' => '_blank', 'escape' => false)
    );
   ?>
  </div>
 </div>
 <?php echo $this->element('sql_dump'); ?>
</body>
</html>

こんな感じになります。

そして、<div class="actions"> の中を書き換えます。

   <div class="actions">
    <h3><?php __('メニュー'); ?></h3>
    <ul>
     <li><?php echo $this->Html->link(__('会員管理', true), array('controller'=>'members','action' => 'index'));?></li>
     <li><?php echo $this->Html->link(__('担当者アカウント管理', true), array('controller' => 'users', 'action' => 'index')); ?> </li>
     <li><?php echo $this->Html->link(__('ログアウト', true), array('controller' => 'users', 'action' => 'logout')); ?> </li>
    </ul>
   </div>

で、一旦このレイアウトを確認します。 /app/controllers/members_controller.php を開いて、 var $name = 'Members'; の下に、

class MembersController extends AppController {

    var $name = 'Members';

    function beforeFilter() {
        $this->layout = 'admin';
    }
とレイアウトの指定を追加します。(上記5〜7行目)

ブラウザで見てみます。

CakePHP1.3で作る会員管理システム(8) フォームの見た目を変える

フォームの見た目を変える

ということで無事 members の会員登録部分が動くようになりました。 すぐに気づくことですが、デフォルトのテンプレートの見た目が気に入らないです。 会員の一覧画面はともかく、 /members/add の登録画面とか。 見た目の整形は最後にまとめてやっても構わない訳ですが、なんだかこのまま作業するのも気が重い。 ここでちょっといじりたい、というのが人情でしょう。 とりあえず、アクション add の場合で言うと、今自動生成されたテンプレートはこうなっています。

 <fieldset>
  <legend><?php __('Add Member'); ?></legend>
 <?php
  echo $this->Form->input('email');
  echo $this->Form->input('password');
  echo $this->Form->input('type_id');
  echo $this->Form->input('birthday');
  echo $this->Form->input('img1');
  echo $this->Form->input('img2');
  echo $this->Form->input('Favorite');
 ?>
 </fieldset>

fieldset とか legend が気に入らないですね。 ということで、本家サイトのドキュメントにあるとおり、デフォルトのテンプレートをコピーして、編集します。

9.3 Modify default HTML produced by "baked" templates

先に、/app/vendors/shells/templates/ 以下に、自分が作るテンプレート用のディレクトリを作っておきます。 ここでは

/app/vendors/shells/templates/mytheme
としました。

そして、

cd Sites/cake/cake/console/templates/default
cp -r views /Users/myname/Sites/cake/app/vendors/shells/templates/mytheme/views
として、デフォルトのテンプレートを自分のところへコピーします。

上記 views の中にある form.ctp を開いて、

 <fieldset>
  <legend><?php printf("<?php __('%s %s'); ?>", Inflector::humanize($action), $singularHumanName); ?></legend>
<?php
  echo "\t<?php\n";
  foreach ($fields as $field) {
   if (strpos($action, 'add') !== false && $field == $primaryKey) {
    continue;
   } elseif (!in_array($field, array('created', 'modified', 'updated'))) {
    echo "\t\techo \$this->Form->input('{$field}');\n";
   }
  }
  if (!empty($associations['hasAndBelongsToMany'])) {
   foreach ($associations['hasAndBelongsToMany'] as $assocName => $assocData) {
    echo "\t\techo \$this->Form->input('{$assocName}');\n";
   }
  }
  echo "\t?>\n";
?>
 </fieldset>
こうなっているところを、
 <h2><?php printf("<?php __('%s %s'); ?>", Inflector::humanize($action), $singularHumanName); ?></h2>
<?php
  echo "\t<?php\n";
  foreach ($fields as $field) {
   if (strpos($action, 'add') !== false && $field == $primaryKey) {
    continue;
   } elseif (!in_array($field, array('created', 'modified', 'updated'))) {
    echo "\t\techo \$this->Form->input('{$field}');\n";
   }
  }
  if (!empty($associations['hasAndBelongsToMany'])) {
   foreach ($associations['hasAndBelongsToMany'] as $assocName => $assocData) {
    echo "\t\techo \$this->Form->input('{$assocName}');\n";
   }
  }
  echo "\t?>\n";
?>
とします。

fieldset と legend を削除して、h2 に変えたってだけです。 再度 cake bake でビューを作り直します。

前回同様yes-noで進んでいくと、今度は、以下のようにテンプレートが選べるメニューが出ます。

---------------------------------------------------------------
You have more than one set of templates installed.
Please choose the template set you wish to use:
---------------------------------------------------------------
1. mytheme
2. default
Which bake theme would you like to use? (1/2) 
[1] > 1
自分が作ったテンプレートを選びます。

/app/views/members/add.ctp を確認すると、

 <h2>
  <?php __('Add Member'); ?></h2>
 <?php
  echo $this->Form->input('email');
  echo $this->Form->input('password');
  echo $this->Form->input('type_id');
  echo $this->Form->input('birthday');
  echo $this->Form->input('img1');
  echo $this->Form->input('img2');
  echo $this->Form->input('Favorite');
 ?>
自分用のテンプレートが適用されています。


CakePHP1.3で作る会員管理システム(7) Validate

Validate

ということで無事 members の会員登録部分が動くようになりました。
ブラウザから、

http://localhost/~myname/cake/members

を開いて、いろいろクリックしたりしてみます。

で、会員の新規登録

http://localhost/~myname/cake/members/add

をやってみると、custom エラーになって登録ができません。

最初に bake でモデルを作った時に、バリデーションの設定で、email と password に custom をセットして、その内容を入れていないのが原因です。
ということで validate をちゃんと作ります。

/app/models/member.php の、 今こうなっているところを

  'email' => array(
   'custom' => array(
    'rule' => array('custom'),
    //'message' => 'Your custom message here',
    //'allowEmpty' => false,
    //'required' => false,
    //'last' => false, // Stop validation after this rule
    //'on' => 'create', // Limit validation to 'create' or 'update' operations
   ),
   'email' => array(
    'rule' => array('email'),
    //'message' => 'Your custom message here',
    //'allowEmpty' => false,
    //'required' => false,
    //'last' => false, // Stop validation after this rule
    //'on' => 'create', // Limit validation to 'create' or 'update' operations
   ),
   'notempty' => array(
    'rule' => array('notempty'),
    //'message' => 'Your custom message here',
    //'allowEmpty' => false,
    //'required' => false,
    //'last' => false, // Stop validation after this rule
    //'on' => 'create', // Limit validation to 'create' or 'update' operations
   ),
  ),

以下のように書き換えます。

  'email' => array(
   'custom' => array(
    'rule' => array('isUnique'),
    'message' => 'このメールアドレスは既に登録されています',
    'on' => 'create', // Limit validation to 'create' or 'update' operations
   ),
   'email' => array(
    'rule' => array('email'),
    'message' => 'メールアドレスを正しく入力してください',
   ),
   'notempty' => array(
    'rule' => array('notempty'),
    'message' => 'メールアドレスを入力してください',
   ),
  ),

パスワードの部分は、以下のように書き換えます。

  'password' => array(
   'custom' => array(
    'rule' => array('custom', '/^[a-zA-Z0-9\_\-]{6,10}$/i'),
    'message' => 'パスワードは6文字以上10文字以内で入力してください',
   ),
   'notempty' => array(
    'rule' => array('notempty'),
    'message' => 'パスワードを入力してください',
   ),
  ),

ソース中に日本語が入りましたので文字コードをutf-8に設定して保存します。
会員の新規登録が出来ることを確認します。


http://localhost/~myname/cake/members/add

このブログを検索

Powered by Blogger.

ラベル

php (17) jQuery (13) OSX (10) MySQL (8) Javascript (7) Postgres (7) port (7) apache (6) Java (3) Smarty (2) html (2) pear (2) FCKEditor (1) XAMPP (1) css (1) git (1) perl (1) ruby (1)

Facebookバナー