RailsによるアジャイルWebアプリケーション開発 第4版中2

どうでもいいところだけど、7章のバリデーションで日本語がエラーになった。
# encoding: utf-8
をつけたら治った。エンコーディングの指定は大事大事。

# encoding: utf-8
class Product < ActiveRecord::Base
  attr_accessible :description, :image_url, :price, :title

  validates :title, :description, :image_url, presence: true
  validates :price, numericality: {greater_than_or_equal_to: 0.01}
  validates :title, uniqueness: true
  validates :image_url, allow_blank: true, format: {
    with: %r{\.(gif|jpg|png)$}i,
    message: "はGIF,JPG,PNG画像のURLでなければなりません。"
  }
end
Posted in rails, ruby | Leave a comment

RailsによるアジャイルWebアプリケーション開発 第4版中。


久々にRailsに戻りました。

サンプルコードは以下より入手できます。
初めての方はこちらからダウンロードしてください。
(実際に手を動かすほうが覚えますけどね。。。)
sample code

Posted in rails, ruby | Leave a comment

sass/scssを使ってみよう

公式サイトはこちらhttp://sass-lang.com/

rubyが必要なので1.9系をインストールしておいてください。

gemを使ってsassのインストール。

gem install sass

これで準備OK。

機能一覧簡略化

コンパイル

    sass --style nested --watch hoge:fuga
    sass --style nested --watch style.scss:style.css

コンパイルタイプ

・nested 親子関係を維持しながらインデント(デフォルトの動作)

・expanded 親子関係無視でベタ書き

・compact 1つのスタイル定義を1行で

・compressed 全部のスタイル定義を1行で

/* */のコメントはコンパイル後も残るが、//コメントはコンパイル後消える。

[記述方法]

scssとsassの2通りの書き方があるが、拡張子で決まるため拡張子と記述方法の対応がとれているかも
重要になってくる。(例:scssのファイルにsassの書き方はできない。)
書き方の違いは好みの違いのようなもの。どちらを選んだとしても問題はない。
但し、AptanaではsassではCSS入力補完をしてくれるが、scssではしてくれない。
ので、個人的にはscssで行こうかなと思います。

記述方法

見ての通りです。親子関係が非常に簡単にかけます。セレクタの&は特殊で親セレクタに勝手に置き換えてくれます。

     #navbar {
       width: 80%;
       height: 23px;
       ul { list-style-type: none; }
     }

   #navbar {
     width: 80%;
     height: 23px; }
     #navbar ul {
       list-style-type: none; }

#main {
  color: black;
  a {
    font-weight: bold;
    &:hover { color: red; }
  }
}
#main {
  color: black; }
  #main a {
    font-weight: bold; }
    #main a:hover {
      color: red; }

2.変数入門

通常の言語同様グローバルスコープとローカルスコープが存在する。
変数の定義方法は下記の通り。

$width1 : 5em;

特に意識しなくても良いが、データ型は以下の5つがある。
numbers (e.g. 1.2, 13, 10px)
strings of text, with and without quotes (e.g. “foo”, ‘bar’, baz)
colors (e.g. blue, #04a3f9, rgba(255, 0, 0, 0.5))
booleans (e.g. true, false)
lists of values, separated by spaces or commas (e.g. 1.5em 1em 0 2em, Helvetica, Arial, sans-serif)

スタイルの外側で定義すればグローバルスコープとなりファイル全体で使用することができる。

  $width1 : 5em;
  #navbar {

    width: $width1;
    height: $width1;
    ul { list-style-type: none; }
  }

  #neko{
    width: $width1;//こっちでも使える
  }

[ローカススコープの例]

  #navbar {
    $width1 : 5em;  //ここに書くとローカルスコープ、このブロック内部でしか使えなくなる。
    width: $width1;
    height: $width1;
    ul { list-style-type: none; }
  }

  #neko{
    width: $width1;//これはエラーになる。
  }

グローバルとローカルスコープに同名の変数は使用することができない。

  $width1 : 5em;
  #navbar {
    $width1 : 3em;
    width: $width1;
    height: $width1;
    ul { list-style-type: none; }
  }

  #neko{
      width: $width1;
  }

↓こう書いた場合、結果は次の様になる。

  #navbar {
    width: 3em;
    height: 3em; }
  #navbar ul {
    list-style-type: none; }

  #neko {
    width: 3em; }

3.関数入門

[email protected]

   @mixin hoge($huga) {
       #neko{
           width: $huga;
       }
   }
  [email protected]
  @include hoge(20px);

結果は下記

  #neko {
    width: 20px; }

変数はいくつでも渡すことができる。
例:ListとNumber型のデータを渡した場合。

@mixin hoge2($foo,$bar) {
      #neko{
          padding: $foo;
          width: $bar;
      }
  }
  @include hoge2(20px 10px 0px 0 , 200px);

結果は下記

#neko {
  padding: 20px 10px 0px 0;
  width: 200px; }

変数をセレクタや文字列内に流しこみをしたい場合には、rubyの#{}
が使用できる。

 @mixin hoge3($foo) {
      #neko #{$foo}{
        padding: 10px;
      }
  }
  @include hoge3(".neko");

結果は下記

#neko .neko {
  padding: 10px; }

引数なし関数

@mixin large-text {
    font: {
      family: Arial;
      size: 20px;
      weight: bold;
    }
    color: #ff0000;
  }

  h1{
    @include large-text;
  }

結果は下記

  h1 {
  font-family: Arial;
  font-size: 20px;
  font-weight: bold;
  color: #ff0000; }

4.制御文(繰り返し構文は使い道がありそう)

@for $i from 1 through 3 {
    .item-#{$i} { width: 2em * $i; }
  }

  @each $animal in puma, sea-slug, egret, salamander {
    .#{$animal}-icon {background-image: url('/images/#{$animal}.png');}
  }

↓これは便利!


  .item-1 {  width: 2em; }
  .item-2 {  width: 4em; }
  .item-3 {  width: 6em; }

  .puma-icon       {  background-image: url("/images/puma.png"); }
  .sea-slug-icon   {  background-image: url("/images/sea-slug.png"); }
  .egret-icon      {  background-image: url("/images/egret.png"); }
  .salamander-icon {  background-image: url("/images/salamander.png"); }

外部ファイルの読み出しとかは今度。

Posted in ruby, sass/scss | Leave a comment

初のPHPフレームワークYiiで行こう!テーブル間のリレーション

[準備]
1.テスト用のdemoアプリを作ります。

php framework/yiic.php webapp demo

2.Mysqlデータベースを使用するため、Mysqlに「demo」というデータベースを
  作成します。

create database demo;

3.データベースとの接続設定を行います。
   Mysqlを使用するためprotected/config/main.php及びconsole.phpを下記の通り
   変更します。

[main.php]及び[console.php]の変更(修正内容は共通です。)

/*
 //sqlliteの記述をコメントアウト。
		'db'=>array(
			'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
		),
		*/
		// uncomment the following to use a MySQL database
		//mysqlの設定を生かす。
		'db'=>array(
			'connectionString' => 'mysql:host=localhost;dbname=demo',//ここはそれぞれの環境による。
			'emulatePrepare' => true,
			'username' => 'xxxxx',//ここはそれぞれの環境による。
			'password' => 'xxxxxxx',//ここはそれぞれの環境による。
			'charset' => 'utf8',
		),

4.giiの準備
[main.php]の変更

	'modules'=>array(
		// uncomment the following to enable the Gii tool

		'gii'=>array(
			'class'=>'system.gii.GiiModule',
			'password'=>'hogehoge',//ここは各自自由なパスワード
		 	// If removed, Gii defaults to localhost only. Edit carefully to taste.
			'ipFilters'=>array('127.0.0.1','::1'),
		),
	),

5.1対1リレーション練習用のテーブルを作ります。
注文書(Order)と請求書(invoice)を下記の通り作成します。
コンソールからdemoアプリのprotectedディレクトリに移動し下記コマンドを
入力します。

php yiic migrate create create_orders_table

php yiic migrate create create_invoices_table

protected/migrationsにファイルが2つできるはずなので、下記のとおり変更します。
[orders]

<?php

class mxxxxxxxxxx_create_orders_table extends CDbMigration
{
    public function safeUp()
    {
        $this->createTable('orders', array(
            'id' => 'pk',
            'name' => 'string NOT NULL',
            'created_at' => 'timestamp'
        ));
    }

    public function safeDown()
    {
        $this->dropTable('orders');
    }
}

[invoice]

<?php

class m120219_234100_create_invoices_table extends CDbMigration
{
    public function safeUp()
    {
        $this->createTable('invoices', array(
            'id' => 'pk',
            'order_id' => 'integer NOT NULL',
            'created_at' => 'timestamp'
        ));
        $this->addForeignKey('fk_invoice_order','invoices','order_id', 'orders', 'id', 'CASCADE', 'CASCADE');
    }

    public function safeDown()
    {
        $this->dropTable('invoices');
    }
}

終わったらマイグレーションの実行。

php yiic migrate

6.giiを使ってモデルを作成。
http://xxxxxxx/demo/index.php?r=giiにアクセスし、Model Generatorを用いてOrdersとinvoicesのモデルを作成します。
※Build Relationsにチェックが入っていることだけ確認。
テーブル名    モデル名
orders   → Order
invoices   → Invoice
とします。
Order.phpのリレーションを確認。下記と違っていたら修正。

invoice' => array(self::HAS_ONE, 'Invoice', 'order_id'),

Invoice.phpのリレーションを確認。下記と違っていたら修正。

'order' => array(self::BELONGS_TO, 'Order', 'order_id'),

ではでは、いよいよ1対1のテストです。
テストするのにいちいちブラウザを起動するのは面倒なので
Shellでやってしまいましょう。
コンソールからdemoアプリのprotectedディレクトリに移動し下記コマンドを
入力します。

 php yiic.php shell ../index.php
$order = new Order();
$invoice = new Invoice();

$order->invoice = $invoice;

$order->name = "neko";
$order->created_at = "2012-02-21 20:10:11";

$invoice->created_at = "2012-02-21 20:15:11";

$order->save();

//これだとinvoiceはsaveされない。
$order->invoice->save();

//order_idを入れた後だと、invoicはsaveされる。
$order->invoice->order_id = $order->id;
$order->invoice->save();

//もちろんそのままでもsaveできる。
echo $invoice->save();

というように、親子のsave方法が結構煩雑です。
このへんを自動化したい場合には、beforeSave等に子のsave処理をいれこんでおくといいですね。

findByPkで検索するとこんなかんじでアクセスできます。

>> $order=Order::model()->findByPk(3);

>> echo $order->name;
neko
>> echo $order->invoice->created_at;

//逆もこんなかんじで。
$invoice=Invoice::model()->findByPk(1);
echo $invoice->order->name;

力尽きたので、続きは明日書きます・・・・。

Posted in PHP, Yii, 未分類 | Leave a comment

[jQuery Mobile] Page Reload

location.reload();

これだけでよかった、なんだぁ~~。
実装はこんな感じにしました。

     	$('#refresh').click(function() {
             location.reload();
       });
Posted in javaScript | Leave a comment

初のPHPフレームワークYiiで行こう!モジュールのレイアウトを使う。

<?php
class XXXXXXXXXModule extends CWebModule
{
	public function init()
	{
		// this method is called when the module is being created
		// you may place code here to customize the module or the application

		// import the module-level models and components
		$this->setImport(array(
			'web_admin.models.*',
			'web_admin.components.*',
		));
		$controller->layout = 'admin';
	}

	public function beforeControllerAction($controller, $action)
	{
		if(parent::beforeControllerAction($controller, $action))
		{
			// this method is called before any module controller action is performed
			// you may place customized code here
            $controller->layout = 'admin';
	 		if (Yii::app()->user->isGuest){
		        throw new CHttpException(403,'You are not authorized to perform this action.');
			}
			return true;
		}
		else
			return false;
	}
}

悩んだけど、$controller->layout = ‘admin’; だけでいいっぽい。
これで、モジュールのlayouts内のファイルを探してくれる。

Posted in PHP, Yii | Leave a comment

[JavaScript,Math]ニュートン補間

3次ニュートン補間練習。 – jsdo.it – share JavaScript, HTML5 and CSS

Posted in javaScript | Leave a comment

初のPHPフレームワークYiiで行こう!メール編

データ吹っ飛んだ・・・。
ということで、単発系記事に一時切り替え。

Yiiバージョン: 1.1.9

ということで、Webappで需要があるメール送信部分を作ってみましょう。

今回はこちらのExtensionを利用させて頂きます。
mailer

1.上記URLよりmailer-2.2.zipをダウンロード。

2.解凍し、出来上がったmailerディレクトリをYiiのprotected/extensionsにコピー

3.protected/config/main.phpを以下のとおり変更する。

// application components
'components'=>array(
・・・・
		'mailer' => array(
			'class' => 'application.extensions.mailer.EMailer',
			'From' => [email protected]',//送信元
			'FromName'=>'ねこみけ',//送信元名
			'CharSet' => 'iso-2022-jp',//メールの文字コード
			'Encoding' => '7bit',
      //以下は送信メールサーバの設定、設定しない場合はlocalhost:25が使用される。
			'Mailer'=>'smtp',
			'Port'=>'587',
			'Host'=> 'xxxxx.jp',
			'SMTPAuth' => true,
			'Username' => [email protected]',
			'Password' => 'xxxxx',
		),

4.protected/config/main.phpを以下のとおり変更し、送信先アドレスを設定する。

	// application-level parameters that can be accessed
	// using Yii::app()->params['paramName']
	'params'=>array(
		// this is used in contact page
		'adminEmail'=>[email protected]',
	),

5.メール本文を記したテンプレートファイルを作成する。

protected/views/emailディレクトリを作成し、その中にcontact.phpを作成する。
また、contact.phpに以下のとおり記載する。

[名前]
<?php echo $name; ?>

[問い合わせ内容]
<?php echo $body; ?>

一応これで下準備が完了。
($nameや$bodyは後ほど説明します。)

6.SiteControllerのメール送信部分の修正

元々のメール送信コードの2行を削除し、$this->send_mailを追加します。

	public function actionContact()
	{
		$model=new ContactForm;
		if(isset($_POST['ContactForm']))
		{
			$model->attributes=$_POST['ContactForm'];
			if($model->validate())
			{
				//$headers="From: {$model->email}\r\nReply-To: {$model->email}";//削除
				//mail(Yii::app()->params['adminEmail'],$model->subject,$model->body,$headers);//削除
				$this->send_mail(Yii::app()->params['adminEmail'],$model->subject,array(
					'name'=>$model->name,
					'body'=>$model->body
				));
				Yii::app()->user->setFlash('contact','Thank you for contacting us. We will respond to you as soon as possible.');
				$this->refresh();
			}
		}
		$this->render('contact',array('model'=>$model));
	}

7.SiteControllerのメール送信を行うsend_mailを追加。

kore

	protected function send_mail($email, $subject, $vars)
	{
		mb_language("ja");
		mb_internal_encoding("UTF-8");
		$mailer =& Yii::app()->mailer;
		$mailer->addAddress($email);
		$mailer->Subject = mb_encode_mimeheader($subject);
		$mailer->getView("contact",$vars);
		$mailer->Body = mb_convert_encoding($mailer->Body,Yii::app()->mailer->CharSet);
		$mailer->send();
	}

この関数自体は、単純な仕事しかしません。
$email・・・送信先のメールアドレス
$subject・・メールのタイトル
$vars・・・5で作成したテンプレートファイル(contact.php)に流し込みたいデータ群。

これでメール送信も完璧?!

おまけ、メールの送信サーバーをgmailにしたい場合。

		'mailer' => array(
			'class' => 'application.extensions.mailer.EMailer',
			'From' => [email protected]',//送信元
			'FromName'=>'ねこみけ',//送信元名
			'CharSet' => 'iso-2022-jp',//メールの文字コード
			'Encoding' => '7bit',
			'Mailer'=>'smtp',
			'Port'=>'587',
			'SMTPSecure'=>'tls',
			'Host'=> 'smtp.gmail.com',
			'SMTPAuth' => true,
			'Username' => [email protected]',
			'Password' => 'xxxxxxxx',
		),

‘SMTPSecure’=>’tls’を追加してください。

Posted in PHP, Yii | Leave a comment

JavaScript日付関連の処理


やっぱり、クックブックはこういう時使えますね。
https://developer.mozilla.org/ja/JavaScript/Reference/Global_Objects/Date

//特定の日付を作りたい。(2000年1月2日)
var old = new Date(2000,0,1);

//出力いろいろ
document.writeln("p old.toLocaleTimeString();<br/>");
document.writeln(old.toLocaleTimeString() + "<br/>");

document.writeln("p old.toLocaleString();<br/>");
document.writeln(old.toLocaleString() + "<br/>");

document.writeln("p old.toLocaleDateString();<br/>");
document.writeln(old.toLocaleDateString() + "<br/>");

document.writeln("p old.toDateString();<br/>");
document.writeln(old.toDateString() + "<br/>");

//今日から10日後の日付を取得したい。
var date = new Date();
date.setDate(date.getDate() +10);

//2つの日付の差を求めたい
var now = new Date();
var between = (function(){
    var initTime = function(d){
	return new Date(d.getFullYear(),d.getMonth(),d.getDate());
    },
    ONE_MINUTE = 1000 * 60,
    ONE_DAY = ONE_MINUTE * 60 * 24,
    ajust,
    diff;
    return function(d1,d2){
	d1 = initTime(d1);
	d2 = initTime(d2);
	if(d2 > d1){
	    ajust = (d2.getTimezoneOffset()-d1.getTimezoneOffset())*ONE_MINUTE;
	}else{
	    ajust = (d1.getTimezoneOffset()-d2.getTimezoneOffset())*ONE_MINUTE;
	}
	diff = Math.abs(d2.getTime() - d1.getTime()) - ajust;
	return Math.ceil(diff/ONE_DAY);
    };
}());
document.writeln(between(now ,new Date(2012,0,25)) + "<br/>");
document.writeln(between(now ,new Date(2012,0,20)) + "<br/>");
document.writeln(between(now ,new Date(2013,0,24)) + "<br/>");

0付き日付の表示
例:2012月2月2日→2012月02月02日

var date = new Date(),
  year = date.getFullYear()*10000,
        month = (date.getMonth() + 1)*100,
        day = date.getDate();
        document.write (( year + month + day +"").replace(/(\d{4})(\d{2})(\d{2})/,"$1年$2月$3日"));

2012-01-24 1st – jsdo.it – share JavaScript, HTML5 and CSS

Posted in javaScript | Leave a comment

初のPHPフレームワークYiiで行こう!9日目

久々の更新になりますが、チェックアウト(カートに入れた商品を購入する)処理へとシフトしていきましょう。
Rails本の第10章ですね。

では、先にデータベースに注文表と注文品目標を作成しちゃいましょう。
テーブルを作るといえばマイグレーションなのでちゃちゃっと作ってしまいましょう。
コンソールでdepot/protectedに移動し以下の2コマンドを実行します。

php yiic migrate create create_orders_table
php yiic migrate create create_line_items_table

ordersのマイグレーションファイルを以下の通り変更。

<?php
class m120121_004306_create_orders_table extends CDbMigration
{
	 public function safeUp()
	    {
	        $this->createTable('orders', array(
	            'id' => 'pk',
	            'name' => 'string NOT NULL',
	            'address' => 'text',
	            'email' => 'string NOT NULL',
	            'pay_type' => 'VARCHAR(10) NOT NULL',
	        ));
	    }

    public function safeDown()
    {
        $this->dropTable('orders');
    }
}

line_itemsのマイグレーションファイルを以下の通り変更。

<?php

class m120121_004330_create_line_items_table extends CDbMigration
{
	 public function safeUp()
	    {
	        $this->createTable('line_items', array(
	            'id' => 'pk',
	            'product_id' => 'integer NOT NULL',
	            'order_id' => 'integer NOT NULL',
	            'quantity' => 'integer NOT NULL',
	            'total_price' => 'money NOT NULL',
	        ));
			$this->addForeignKey('fk_line-item_products','line_items','product_id', 'products', 'id', 'CASCADE', 'CASCADE');
			$this->addForeignKey('fk_line-item_orders','line_items','order_id', 'orders', 'id', 'CASCADE', 'CASCADE');
	    }

    public function safeDown()
    {
        $this->dropTable('line_items');
    }
}

あとは、giiを使ってモデルを作っておきましょう。
モデル名は、「LineItem」と「Order」にしておきましょう。

では、外部制約を追加したLineItemを見てみると、OrdersとProductsになっている箇所を
単数形に修正する必要があります。

	/**
	 * @return array relational rules.
	 */
	public function relations()
	{
		// NOTE: you may need to adjust the relation name and the related
		// class name for the relations automatically generated below.
		return array(
			'order' => array(self::BELONGS_TO, 'Order', 'order_id'),
			'product' => array(self::BELONGS_TO, 'Product', 'product_id'),
		);
	}

これでAtiveRecord側のリレーション設定も完了します。
また、Orderにも同様にリレーション設定がされていますが、Productはまだなので追記しておきます。
(Order側も単数形に訂正しておきます。)
Product.phpのrelationsを以下の通り変更。

	public function relations()
	{
		// NOTE: you may need to adjust the relation name and the related
		// class name for the relations automatically generated below.
		return array(
			'lineItems' => array(self::HAS_MANY, 'LineItem', 'product_id'),
		);
	}

Order.phpのrelationsを以下の通り変更。

	public function relations()
	{
		// NOTE: you may need to adjust the relation name and the related
		// class name for the relations automatically generated below.
		return array(
			'lineItems' => array(self::HAS_MANY, 'LineItem', 'order_id'),
		);
	}

こうすることで、Railsと同様に1対多のリレーション設定が簡単に終わります。
(このへんは後で実験したいですね)

ではでは、準備ができたので、注文受付フォームを作ってみましょう。
まずは、storeコントローラーにcheckoutアクションで処理をさせるため、カート部分にチェックアウトへのリンクを作っておきましょう。
_cart.phpを以下の通り変更。

_cart.phpを以下の通り変更。

<div class="cart">
	<h2>Shopping Cart</h2>
<span class="open menu" >▼</span>
<span class="cart_total"><?php echo count($cart->items)."アイテム".$this->cn->formatCurrency($cart->total_price(),"JPY"); ?></span>

	<div class="cart_items" style="display:none;">

		<?php $this->renderPartial('_cart_item',array(
				'cart' => $cart,
				'items'=>$cart->items,
			)); ?>
		<?php
			//追加(ここから)
			echo CHtml::submitButton('チェックアウト',array(
						'type'=>'post',//postで送って
						'submit' => Yii::app()->createUrl($this->id.'/checkout'),
						'id'=>"checkout"
						)
			);
			//追加(ここまで)
			echo CHtml::submitButton('カートを空にする',array(
						'type'=>'post',//postで送って
						'submit' => Yii::app()->createUrl($this->id.'/empty_cart'),
						'id'=>"empty_cart"
						)
			);
		?>
	</div>
</div>

storeControllerにcheckoutアクションの追加

	public function actionCheckout(){
		$this->cn=new CNumberFormatter('ja');
		$this->cart = $this->find_cart();
		if(empty($this->cart->items)){
			$this->redirect_to_index('notice', 'カートは現在空です');
		}else{
			$order = new Order();
			$this->render('checkout',array(
				'model'=>$order,
			));
		}
	}

checkout ビューファイルを以下のとおり作成。

ファイル:view/store/checkout.php

<div class="form">

<?php $form=$this->beginWidget('CActiveForm', array(
	'id'=>'checkout-form',
	'action'=>'save_order',
	'focus'=>array($model,'name'),
	'enableAjaxValidation'=>false,
)); ?>

	<p class="note"><span class="required">*</span>は必須入力です。</p>

	<?php echo $form->errorSummary($model); ?>

	<div class="row">
		<?php echo $form->labelEx($model,'name'); ?>
		<?php echo $form->textField($model,'name',array('size'=>40,'maxlength'=>255)); ?>
		<?php echo $form->error($model,'name'); ?>
	</div>

	<div class="row">
		<?php echo $form->labelEx($model,'address'); ?>
		<?php echo $form->textArea($model,'address',array('rows'=>3, 'cols'=>40)); ?>
		<?php echo $form->error($model,'address'); ?>
	</div>

	<div class="row">
		<?php echo $form->labelEx($model,'email'); ?>
		<?php echo $form->textField($model,'email',array('size'=>40,'maxlength'=>255)); ?>
		<?php echo $form->error($model,'email'); ?>
	</div>
	<div class="row">
		<?php echo $form->labelEx($model,'pay_type'); ?>
		<?php echo $form->dropDownList($model,'pay_type',Order::$PAYMENT_TYPES,array(
			'prompt'=>'お支払い方法を選択してください'
		)); ?>
		<?php echo $form->error($model,'pay_type'); ?>
	</div>
	<div class="row buttons">
		<?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
	</div>

<?php $this->endWidget(); ?>

</div><!-- form -->

最後に支払い方法をOrderクラスに定義

それに伴いバリデーションルールも一部追加。

class Order extends CActiveRecord
{
   static public $PAYMENT_TYPES=array(
   	'check'=>'現金',
   	'cc'=>'クレジットカード',
   	'po'=>'注文書',
   );
	public function rules()
	{
		// NOTE: you should only define rules for those attributes that
		// will receive user inputs.
		return array(
			array('name, email, pay_type,address', 'required'),
			array('name, email', 'length', 'max'=>255),
			array('pay_type', 'length', 'max'=>10),
			array('pay_type', 'in', 'range'=>array_keys (Order::$PAYMENT_TYPES)),//追加

			// The following rule is used by search().
			// Please remove those attributes that should not be searched.
			array('id, name, address, email, pay_type', 'safe', 'on'=>'search'),
		);
	}

あとは、特に難しいところもないので、注文完了処理を作ってしまいましょう。
StoreController.phpにactionSave_orderを追加。
どうやら、Yiiではリレーションを組んでいても、親を保存した場合、子の保存は行ってくれないため、
自力でコード実装するしかありません。(なんだかな・・・。ちょっと問題のあるコードですが練習ってことで)

	public function actionSave_order(){
		$this->cn=new CNumberFormatter('ja');
		$this->cart = $this->find_cart();
		$order = new Order();
		if(isset($_POST['Order']))
		{
			$order->attributes=$_POST['Order'];
			if($order->save()){
				$order->add_line_items_from_cart($this->cart);
				Yii::app()->session['cart'] = NULL;
				$this->redirect_to_index("notice","ご注文ありがとうございます");
			}
		}

		$this->render('checkout',array(
			'model'=>$order,
		));
	}

Order.phpにadd_line_items_from_cartを追加。

	public function add_line_items_from_cart($cart){
		$lineitem = NULL;
		foreach($cart->items as $item){
			$lineitem = LineItem::from_cart_item($item);
			$lineitem->order_id = $this->id;
			$lineitem->save();
		}
	}

LineItems.phpにfrom_cart_itemを追加。

	static public function from_cart_item($cart_item){
		$li = new self();
		$li->product_id = $cart_item->product->id;
		$li->quantity = $cart_item->quantity;
		$li->total_price = $cart_item->price();
		return $li;
	}

一応これでチェックアウト周りも完了だと思います。
リレーション周りがしっくり来ませんがそのうちまとめます。

Posted in PHP, Yii | Leave a comment