しのさん協力■sfPageFlowを使っての新規作成■ ■PROJECT作成「プロジェクト名」 一般ユーザでログインし以下を入力 mkdir プロジェクト名 cd プロジェクト名 symfony init-project プロジェクト名 ■Application作成 「front」 「backend」 symfony init-app front symfony init-app backend ■apacheの設定を変更 suでrootへ変更。 /etc/httpd/conf/httpd.confに以下を記述 vi /etc/httpd/conf/httpd.conf <VirtualHost *:80> ServerName www.プロジェクト名(任意).jp DocumentRoot /home/ユーザー名/プロジェクト名/web <Directory "/home/ユーザー名/プロジェクト名/web"> AllowOverride All Options -Includes -ExecCGI </Directory> </VirtualHost> ■5.Apache再起動 /etc/init.d/httpd restart 実行 httpd を停止中: [ OK ] httpd を起動中: [ OK ] ---------------------------------------- ■C:\Windows\System32\drivers\etc\hostsに 127.0.0.1(サーバのIP) www.shonanbbs.com 192.168.0.128 www.プロジェクト名.jp 192.168.0.128 www.プロジェクト名.jp 表示を確認。 ---------------------------------------- ■symfony設定ファイルのシンボリックリンク作成 cd /home/ユーザー名/プロジェクト名/web/ ln -s /usr/share/pear/data/symfony/web/sf ./sf ◆DB/カラム作成 mysql -u rootで入って作成 CREATE DATABASE enojo; ■MySQLユーザーを作成して権限付与 GRANT ALL ON DB名.* TO ユーザー名@"localhost" IDENTIFIED BY "password"; flush privileges; ◆テーブル作成 ■テーブル作成 ●member CREATE TABLE member(id int not null auto_increment primary key); ALTER TABLE member ADD comment_id int not null; ALTER TABLE member ADD sei varchar(255); ALTER TABLE member ADD mei varchar(255); ALTER TABLE member ADD sei_kana varchar(255); ALTER TABLE member ADD mei_kana varchar(255); ALTER TABLE member ADD nickname varchar(255); ALTER TABLE member ADD pass text; ALTER TABLE member ADD photo1 text; ALTER TABLE member ADD gender tinyint(1); ALTER TABLE member ADD zip_code int(7); ALTER TABLE member ADD pref tinyint(2); ALTER TABLE member ADD address1 varchar(255); ALTER TABLE member ADD address2 varchar(255); ALTER TABLE member ADD address3 varchar(255); ALTER TABLE member ADD tel varchar(11); ALTER TABLE member ADD email varchar(255); ALTER TABLE member ADD note text; ALTER TABLE member ADD update_at datetime; ALTER TABLE member ADD create_at datetime; ALTER TABLE member ADD del_flg tinyint(1); ●reply create table reply(id int not null auto_increment primary key); ALTER TABLE reply ADD comment_id int not null; ALTER TABLE reply ADD name varchar(255); ALTER TABLE reply ADD content varchar(255); ALTER TABLE reply ADD photo1 text; ALTER TABLE reply ADD photo2 text; ALTER TABLE reply ADD email varchar(255); ALTER TABLE reply ADD reply_cnt int; ALTER TABLE reply ADD create_at datetime; ALTER TABLE reply ADD del_flg tinyint(1); ●comment create table comment(id int not null auto_increment primary key); ALTER TABLE comment ADD comment_id int not null; ALTER TABLE comment ADD content text; ALTER TABLE comment ADD categorie int; ALTER TABLE comment ADD photo1 text; ALTER TABLE comment ADD photo2 text; ALTER TABLE comment ADD photo3 text; ALTER TABLE comment ADD note text; ALTER TABLE comment ADD access_cnt int; ALTER TABLE comment ADD create_at datetime; ALTER TABLE comment ADD update_at datetime; ALTER TABLE comment ADD del_flg tinyint(1); ■テーブル構造の確認 show databases; describe member; describe reply; describe study; ■テーブルの確認 show tables; ■カラムを削除。 ALTER TABLE member drop comment_id; ALTER TABLE member drop memo; ◆プロジェクト作成 symfony propel-build-schema symfony propel-build-model ■web/backendディレクトリ作成 cd /home/ユーザー名/プロジェクト名/web mkdir backend mv backend.php backend_dev.php ./backend cp .htaccess ./backend ■.htaccessの内容を変更 cd backend vi .htaccess ■RewriteBaseとRewriteRuleを以下のように変更 Options +FollowSymLinks +ExecCGI <IfModule mod_rewrite.c> RewriteEngine On # uncomment the following line, if you are having trouble # getting no_script_name to work RewriteBase / # we skip all files with .something RewriteCond %{REQUEST_URI} \..+$ RewriteCond %{REQUEST_URI} !\.html$ RewriteRule .* - [L] # we check if the .html version is here (caching) RewriteRule ^$ index.html [QSA] RewriteRule ^([^.]+)$ $1.html [QSA] RewriteCond %{REQUEST_FILENAME} !-f # no, so we redirect to our front web controller RewriteRule ^(.*)$ /backend/backend.php [QSA,L] </IfModule> # big crash from our front web controller ErrorDocument 500 "<h2>Application error</h2>symfony application failed to start properly" ■web/backend/backend.phpを以下のように修正 define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/..')); ↓ define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/../..')); ■/home/sheena/hunt/apps/front/config/view.ymlを開き、 title、description、keywords を変更する 終了後symfony cc ■データベースへの接続情報を設定する プロジェクト名/config/databases.yml を開く all: propel: class: sfPropelDatabase param: dsn: mysql://ユーザー名:password@localhost/プロジェクト名 encoding: utf8 ■プロジェクト名/config/propel.iniを開き、以下の2項目を修正する propel.database.createUrl = mysql://ユーザー名:password@localhost propel.database.url = mysql://ユーザー名:password@localhost/プロジェクト名 ◆sfPageFlow(Model名はlib/model参照。最初が大文字なら合わせる。) 管理者用会員情報 symfony propel-generate-create backend default Member symfony propel-generate-edit backend default Member symfony propel-generate-list backend default Member 管理者用コメント管理 symfony propel-generate-list backend comment_edit Comment ログイン symfony propel-generate-create front login Member ログアウト symfony propel-generate-create front logout Member 一般用新規登録 symfony propel-generate-create front member_add Member 新規投稿 symfony propel-generate-create front default Comment symfony propel-generate-list front default Comment 返信 symfony propel-generate-create front reply_add Reply 投稿管理 symfony propel-generate-edit front comment_edit Comment 必要なもの /lib/helper/ MyUtilityHelper.zip解凍後のMyUtilityHelper.phpでおk /apps/front/templates _pager.php /apps/front/lib myUser.class.php actionにある下記をCommentPeer.phpへ移動 static public function getPager($perpage, $page, $parameters) { $c = new Criteria(); //$c->addDescendingOrderByColumn(self::CREATED_AT); $pager = new sfPropelPager('Comment', $perpage); $pager->setCriteria($c); $pager->setPage($page); $pager->init(); return $pager; } このままだと編集できないので <a href="/comment_edit/flow?id=<?php echo $item->getId();?>">edit</a> を追加
2011年4月28日木曜日
4/28覚書
ラベル:
sfPageFlow,
Symfony,
講座
4/25覚書
腰痛きついいいい。ちくしょー。
4時間目から登校。
☆sfPageFlow
めんどくさい投稿、編集、完了を一気にやってくれるプラグイン。
最初の解凍方法で詰まったっす・・・・
ええとまずgenerator.zipを自分のプロジェクト直下にFTPでUP。
mv generator.zip /usr/share/pear/data/symfony/
そのあとsuでrootログインして移動
cd /usr/share/pear/data/symfony/
解凍失敗してたファイルを移動
mv generator bk.generator
再度解凍
unzip generator.zip
あとは教科書通りで。
rootに入ったときはcd /home/で入るよ。ってすっかり忘れてたよ・・・。
課題がBBS焼き直しなのでそのまま入った。
symfony propel-generate-create backend member_add Member
symfony propel-generate-edit backend member_edit Member
symfony propel-generate-list backend member_list Member
4時間目から登校。
☆sfPageFlow
めんどくさい投稿、編集、完了を一気にやってくれるプラグイン。
最初の解凍方法で詰まったっす・・・・
ええとまずgenerator.zipを自分のプロジェクト直下にFTPでUP。
mv generator.zip /usr/share/pear/data/symfony/
そのあとsuでrootログインして移動
cd /usr/share/pear/data/symfony/
解凍失敗してたファイルを移動
mv generator bk.generator
再度解凍
unzip generator.zip
あとは教科書通りで。
rootに入ったときはcd /home/で入るよ。ってすっかり忘れてたよ・・・。
課題がBBS焼き直しなのでそのまま入った。
symfony propel-generate-create backend member_add Member
symfony propel-generate-edit backend member_edit Member
symfony propel-generate-list backend member_list Member
書きかけ if(!$member){ $this->redirect('testmember_list/index') } <a href="/testmember_list/index?delete=on&id=<?php echo $item->getId()?>"> <a onclick="return confirm('削除しますか?');" href=
ラベル:
sfPageFlow,
Symfony,
講座
2011年4月25日月曜日
4/25覚書
色々あってかなり間が空いた。その色々は主に金銭面だが。
1時間目
☆エラーチェック
frontにmember_addモジュール作成。
以下記述
1.値を渡す先のaction名.ymlをvalidateディレクトリに置く。
confrim.yml作成
2.validate/action名.ymlにエラーチェックのルールを記述する。
confirm.ymlに以下記述
handleErroraction名で作成する。
2時間目
4.エラーメッセージを表示させる。
出たけどこの謎矢印はSymfonyが出してるのか・・・。
configのsettings.ymlを以下修正。ALLの#もあったら取ろう。
片方だけ入力すると、入力した値は消えずに残っている。SymfonySUGEEEEE。
仕組みはhandelErrorConfirmでforwordが値を内部的に保持してくれている。
それを$sf_paramsが受け取っているから表示できる。
☆応用 if文でエラーチェック。
strictは正規表現のvalidate。ただ、strictをつけると携帯のメールがはじかれる?
数字のvalidater
3時間目
☆比較Validater
4時間目
☆自作Validator
おまけ
以降は自習。validate処理追加していこう。とな。
なんとか自前のmember_addに入れられた・・・はふー。
1時間目
☆エラーチェック
frontにmember_addモジュール作成。
以下記述
<?php use_helper('Validation');?> ←Validationヘルパー呼び出し <form action="/backend/member_add/confirm" method="POST"> 名前:<input type="text"name="name" value="<?php echo $sf_params->get('name')?>"><br> <?php echo form_error('name');?> メールアドレス:<input type="text"name="mail" size="30" value="<?php echo $sf_params->get('mail')?>"> <?php echo form_error('mail');?> <br> <input type="submit" name="send" value="確認"> </form>
1.値を渡す先のaction名.ymlをvalidateディレクトリに置く。
confrim.yml作成
2.validate/action名.ymlにエラーチェックのルールを記述する。
confirm.ymlに以下記述
fields: name: required: msg: ニックネームを入力してください。 mail: required: msg: メールアドレスを入力してください。 sfEmailValidator: email_error: メールアドレスを正しく入力してください。3.エラーだった場合の遷移先をactionで定義する。
handleErroraction名で作成する。
public function handleErrorConfirm() { $this->forward('member_add' , 'input'); }
2時間目
4.エラーメッセージを表示させる。
fields: name: required: msg: ニックネームを入力してください。 mail: required: msg: メールアドレスを入力してください。
出たけどこの謎矢印はSymfonyが出してるのか・・・。
configのsettings.ymlを以下修正。ALLの#もあったら取ろう。
# validation_error_prefix: ' ↓ ' # validation_error_suffix: ' ↓'の#と↓ 、 ↓を消す。
片方だけ入力すると、入力した値は消えずに残っている。SymfonySUGEEEEE。
仕組みはhandelErrorConfirmでforwordが値を内部的に保持してくれている。
それを$sf_paramsが受け取っているから表示できる。
☆応用 if文でエラーチェック。
<?php if($sf_request->haserror('name')):?> <div style="background-color:#ff0000;"> <?php echo form_error('name');?> </div> <?php endif;?>
strictは正規表現のvalidate。ただ、strictをつけると携帯のメールがはじかれる?
数字のvalidater
sfNumberValidator: num_error: 整数を入力してください min: 0 min_error: 値は最小0でなければなりません。 max: 100 max_error: 値は100以下でなければなりません。
3時間目
☆比較Validater
4時間目
☆自作Validator
member_addのconfirm.ymlのnameのすぐ後に以下追加 myNameValidator: name_error: そのニックネームはすでに使われています。
module直下のlibディレクトリに作成。 myname(ymlと同じ)validator.class.php その中身 <?php class myNameValidator extends sfValidator { public function execute(&$value, &$error) { //actionではないので呼び出し処理が必要 $request = sfContext::getInstance()->getRequest(); $user = $this->getContext()->getUser; $c = new Criteria(); $c ->add (MemberPeer::NICKNAME, $request->getParameter('name')); $count = MemberPeer::doCount($c); if ($count !=0){ $error ='このニックネームはすでに使用されています。'; return false; } return true; } } ?>
おまけ
出力したエラーメッセージのクラスは以下 <div style="" class="form_error" id="error_for_mail"> メールアドレスを入力してください。 </div> default→configのsettings.ymlのValidate箇所で変更可能。 main.cssでCSS設定もおk。
以降は自習。validate処理追加していこう。とな。
なんとか自前のmember_addに入れられた・・・はふー。
2011年4月15日金曜日
4/15覚書
腰痛+バイト面接で課題-3日。
さてがんばるか~。
☆制作課題
1.システム概要
・どんなシステムを作るか
・ターゲットユーザー
・収益モデル
等々
2.DBテーブル構成
3.アプリケーション・モジュール作成
4.各モジュールページ遷移図
全く考えてなかった。
2時間目も考えるが見事なまでに何もでない。
1.システム概要
・どんなシステムを作るか
→アフィリエイト+釣果掲示板
・ターゲットユーザー
→釣り人(海)LT系
・収益モデル
→楽天のアフィリ収益
等々
2.DBテーブル構成
まあBBSとほぼ一緒。
3.アプリケーション・モジュール作成
4.各モジュールページ遷移図
で、こんなのできた。
自宅でやります・・・・・・。
テーブル名とカラム名は同じにしないって一言が・・・・・・あれ? 似たようなことを前に聞いた気がする。
さてがんばるか~。
☆制作課題
1.システム概要
・どんなシステムを作るか
・ターゲットユーザー
・収益モデル
等々
2.DBテーブル構成
3.アプリケーション・モジュール作成
4.各モジュールページ遷移図
全く考えてなかった。
2時間目も考えるが見事なまでに何もでない。
1.システム概要
・どんなシステムを作るか
→アフィリエイト+釣果掲示板
・ターゲットユーザー
→釣り人(海)LT系
・収益モデル
→楽天のアフィリ収益
等々
2.DBテーブル構成
まあBBSとほぼ一緒。
3.アプリケーション・モジュール作成
4.各モジュールページ遷移図
で、こんなのできた。
自宅でやります・・・・・・。
テーブル名とカラム名は同じにしないって一言が・・・・・・あれ? 似たようなことを前に聞いた気がする。
2011年4月11日月曜日
4/11覚書
1時間目自習
mypage未作成の人が居るためでらっち奔走。
mypageとかのfront以外のアプリ追加手順はこの日記を参照してほしい。
2時間目
mypageのlayout設定。
CSSはシンボリックリンクでfrontと同じにする。
ln -s ../css cssを使う。
ヘッダーとフッターをpartial化。
あとはパンくずとslotでつける。
ほかレイアウト調整。
3時間目
認証と権限の解説復習。
てかprint_r($this->getUser());こええええ。
丸わかりすぎ。
CCSでヘッダの下に追記
4時間目
mypageにログアウト、indexに遷移する処理。
ここはまんまbackendと同じなので省略~。
sessionからmember_idを元にデータを引き出す。
今日の材料はメールでデータがあるからそれ参考で。
5時間目
commentテーブルにmemberテーブルと紐付けるテーブル追加
ALTER TABLE comment ADD member_id int;
6時間目
comment_editを表示させる。
ケアレスミスに数時間_| ̄|○
action側
input
confirm
明日から実習
水曜午後から企画発表
・どのようなアプリにするか
・DB構成
・可能ならページ遷移
・アプリケーション、モジュールの構成
mypage未作成の人が居るためでらっち奔走。
mypageとかのfront以外のアプリ追加手順はこの日記を参照してほしい。
2時間目
mypageのlayout設定。
CSSはシンボリックリンクでfrontと同じにする。
ln -s ../css cssを使う。
ヘッダーとフッターをpartial化。
layout <?php include_partial("global/header");?> _header <div id="header"> <a href="/">SHONANBBS</a> ようこそ<?php echo $sf_user->getAttribute('nickname',NULL,sfConfig::get('sf_session_name'));?> </div>
あとはパンくずとslotでつける。
ほかレイアウト調整。
3時間目
認証と権限の解説復習。
てかprint_r($this->getUser());こええええ。
丸わかりすぎ。
CCSでヘッダの下に追記
#headerLeft { width: 200px; float:left } #headerRight { width: 200px; float:right; text-align:right; }
4時間目
mypageにログアウト、indexに遷移する処理。
ここはまんまbackendと同じなので省略~。
sessionからmember_idを元にデータを引き出す。
今日の材料はメールでデータがあるからそれ参考で。
5時間目
commentテーブルにmemberテーブルと紐付けるテーブル追加
ALTER TABLE comment ADD member_id int;
6時間目
comment_editを表示させる。
ケアレスミスに数時間_| ̄|○
action側
<?php /** * comment_edit actions. * * @package bbs2 * @subpackage comment_edit * @author Your name here * @version SVN: $Id: actions.class.php 2692 2006-11-15 21:03:55Z fabien $ */ class comment_editActions extends sfActions { /** * Executes index action * */ public function executeInput() { $comment_id = $this->getRequestParameter('id'); $this->comment = CommentPeer::retrieveByPK($comment_id); if ($this->comment != '' && $this->comment->getMemberId() != $this->getUser()->getAttribute('member_id', null, sfConfig::get('sf_session_name'))){ $this->redirect('http://www.shonanbbs.com'); } return sfView::SUCCESS; } public function executeConfirm() { $this->id = $this->getRequestParameter('id'); $this->content = $this->getRequestParameter('content'); return sfView::SUCCESS; } public function executeResult() { $content = $this->getRequestParameter('content'); $comment_id = $this->getRequestParameter('id'); $comment = CommentPeer::retrieveByPK($comment_id); $comment->setContent($content); $comment->save(); return sfView::SUCCESS; } }
input
<?php slot('pankuzu');?> <?php echo link_to("HOME","/mypage")?> > コメント編集<?php end_slot();?> <?php slot('sidemenu');?> <?php include_partial("global/menu", array('now' => 'home'));?> <?php end_slot();?> 登録情報更新 <br> <div class="tblData"> <?php echo form_tag("/comment_edit/confirm","method=post multipart=true") ?> <table> <td>コメント:<?php echo input_tag("content", $comment->getContent() , array("size => 20"))?><br> <?php echo input_hidden_tag('id', $comment->getId());?> <input type="submit" name="send" value="確認"> </table> </form> </div>
confirm
<div class="tblData"> <?php echo form_tag("/comment_edit/result","method=post multipart=true") ?> <table> <tr> <th>名前</th> <td><?php echo $content?> <?php echo input_hidden_tag('content', $content);?> </td> </tr> </table> </div> <?php echo input_hidden_tag('id',$id);?> <?php echo submit_tag('完了');?>
明日から実習
水曜午後から企画発表
・どのようなアプリにするか
・DB構成
・可能ならページ遷移
・アプリケーション、モジュールの構成
2011年4月8日金曜日
4/8覚書
1時間目
CSS適用ができねえええええ。
とおもったら。
ln -s ../css css
自分のログで大文字で書いてた(テペペロ☆
2時間目
comment_listで
コメントと名前とカテゴリの編集をできるようにする。ヒントはreply_add。
exで画像のようだがそこまではムリポ。
3時間目
☆symfonyのアクセス制御
管理画面、マイページなどのように認証されたユーザで
特定の権限を持つユーザだけが閲覧や操作を行えるようにする。
/bbs2/lib/model/MemberPeer.php
4時間目
☆認証
symfonyは、アクセスしているユーザに関する情報はユーザークラス($this->getUser())が持っている。
ユーザクラスに権限の情報を付与・削除することと、各アプリケーションごと、
モジュールごとのsecurity.ymlでアクセス制御を実現する。
認証済みかどうか $this->getUser()->isAuthenticated();
どの権限を持つかどうか $this->getUser()->hasCredential("member");
この二つを主に利用する。
制限のルールを書くのはsecurity.ymlで行う。
/backend/config/security.ymlに以下のように記述
権限管理を行うこともできる。
あと複数設けることもできるが、orにしたい場合は
credentials: [[member,admin]]のようになる。
backendにlogoutモジュール作成して
ログアウト処理。backendからアウトしてTOPへ。
action側(しか要らない)
ログイン処理+α TOPからのリンク。をやりました。まとめソース↓
5時間目
admin_ynカラム追加してif文で判定。
$this->getUser()->setAttribute('member_id', $member->getId(),sfConfig::get('sf_session_name'));
第3引数はセッション内に名前空間(name_space)を必ず設定。
区切りでセットすることで区切りごと削除が可能となる。
sesstion_nameはプロジェクト直下のconfigのsetting.ymlに記述。
☆練習問題
mypageアプリケーション作成
権限Credentialはmemberを指定
adminとmemberでログインしたあとの遷移を変更。
てか最終的な情報しか残せなかたよ。ごめんよー。
frontのloginモジュール、action側
frontのloginモジュール、index側
mypageログイン時TOP表示。
mypageのsecurity.yml
action側
mypageのindex。
mypageのaction。
でけた。
ていうか現状ではlogoutがbackendしかないからmypageでログアウトするのって
ログインしなおすんだよね・・・・・・権限で判定??
補足設定
backendのsettings.ymlを下記に変更。
# timeout: 1800 # Session timeout, in seconds
だよー。
来週は自分のプロフィールや投稿のみ編集可能にする。
とバリデートするそーな。
自分的お勧め
PHPエラーの意味を教えてくれるところ
CSS適用ができねえええええ。
とおもったら。
ln -s ../css css
自分のログで大文字で書いてた(テペペロ☆
2時間目
comment_listで
コメントと名前とカテゴリの編集をできるようにする。ヒントはreply_add。
exで画像のようだがそこまではムリポ。
3時間目
☆symfonyのアクセス制御
管理画面、マイページなどのように認証されたユーザで
特定の権限を持つユーザだけが閲覧や操作を行えるようにする。
/bbs2/lib/model/MemberPeer.php
static public function retrieveByPassword($mailaddress,$password) { $c = new Criteria(); $c->add(self::MAILADDRESS, $mailaddress); $c->add(self::PASSWORD, $password); return self::doSelectOne($c); }
4時間目
☆認証
symfonyは、アクセスしているユーザに関する情報はユーザークラス($this->getUser())が持っている。
ユーザクラスに権限の情報を付与・削除することと、各アプリケーションごと、
モジュールごとのsecurity.ymlでアクセス制御を実現する。
認証済みかどうか $this->getUser()->isAuthenticated();
どの権限を持つかどうか $this->getUser()->hasCredential("member");
この二つを主に利用する。
制限のルールを書くのはsecurity.ymlで行う。
/backend/config/security.ymlに以下のように記述
all: is_secure: on #認証済みの必要がある credentials: [ member ] #必要な権限を設定するモジュールにもsecurity.ymlを置いて上記のように記述することでモジュールごとの
権限管理を行うこともできる。
あと複数設けることもできるが、orにしたい場合は
credentials: [[member,admin]]のようになる。
backendにlogoutモジュール作成して
ログアウト処理。backendからアウトしてTOPへ。
action側(しか要らない)
public function executeIndex() { //未認証にする $this->getUser()->setAuthenticated(false); //権限をクリア $this->getUser()->clearCredentials(); //TOPへ移動 $this->redirect('http://www.shonanbbs.com''); return sfView::SUCCESS; }ログイン処理→ログインできたらログアウト→defaultへ遷移。
ログイン処理+α TOPからのリンク。をやりました。まとめソース↓
5時間目
admin_ynカラム追加してif文で判定。
$this->getUser()->setAttribute('member_id', $member->getId(),sfConfig::get('sf_session_name'));
第3引数はセッション内に名前空間(name_space)を必ず設定。
区切りでセットすることで区切りごと削除が可能となる。
sesstion_nameはプロジェクト直下のconfigのsetting.ymlに記述。
☆練習問題
mypageアプリケーション作成
権限Credentialはmemberを指定
adminとmemberでログインしたあとの遷移を変更。
てか最終的な情報しか残せなかたよ。ごめんよー。
frontのloginモジュール、action側
public function executeIndex() { $this->mailaddress = $this->getRequestParameter('mailaddress'); $this->password = $this->getRequestParameter('password'); if ($this->mailaddress != '' && $this->password != '') { //メンバーテーブルに入力されたメールアドレス、パスワードで //指定出来る行があるかどうか //MemberPeerに$this->mailaddress, $this->passwordの引数を渡す $member = MemberPeer::retrieveByPassword ($this->mailaddress, $this->password); if ($member){ // ログイン状態にする //認証処理は$this->getUser()で受け取れるuserオブジェクトで //設定できる。セッション名をいちいち変えなくていい。 $this->getUser()->setAuthenticated(true); //権限をクリア $this->getUser()->clearCredentials(); // 会員情報をセッションにセット $this->getUser()->setAttribute('member_id', $member->getId(),sfConfig::get('sf_session_name')); $this->getUser()->setAttribute('nickname', $member->getNickname(), sfConfig::get('sf_session_name')); if($member->getAdminYn() == 'y') { //admin権限付与 $this->getUser()->addCredential('admin'); $this->redirect('/backend'); }elseif ($member->getAdminYn() == 'n') { //ここでは一般会員権限のみ付与 $this->getUser()->addCredential('member'); // 会員情報をセッションにセット $this->getUser()->setAttribute('member_id', $member->getId(),sfConfig::get('sf_session_name')); $this->getUser()->setAttribute('nickname', $member->getNickname(), sfConfig::get('sf_session_name')); $this->redirect('/mypage'); } } $this->errormsg = "あてはまるユーザが登録されていません"; } return sfView::SUCCESS; }
frontのloginモジュール、index側
<?php slot('pankuzu');?>HOME<?php end_slot();?> <?php slot('title');?> TOP <?php end_slot();?> <?php slot('sidemenu');?> <?php include_partial("global/menu", array('now' => 'login'));?> <?php end_slot();?> <?php use_helper('Validation') ?> <?php echo form_tag('login/index');?> <div class="tblData"> <?php if ($errormsg != ''):?> <div><?php echo $errormsg;?></div> <?php endif;?> <table> <tr> <th>メールアドレス</th> <td <?php if ($sf_request->haserror('mailaddress')) :?> style="background-color:#ffcccc;" <?php endif;?>> <?php echo input_tag('mailaddress', $mailaddress, array('size' => 50));?> <?php echo form_error('mailaddress');?></td> </tr> <tr> <th>パスワード</th> <td><?php echo input_tag('password', $password, array('size' => 50));?> <?php echo form_error('password');?></td> </tr> </table> </div> <?php echo submit_tag('ログインする');?> </form>
mypageログイン時TOP表示。
mypageのsecurity.yml
default: is_secure: on credentials: [ member ]
action側
public function executeIndex() { $this->getUser() -> getAttribute('member_id', NULL,sfConfig::get('sf_session_name')); $this->member = MemberPeer::retrieveByPK($member_id); //$this->comments = CommentPeer::retrieveByComment_Id($cooment_id) return sfView::SUCCESS; }
mypageのindex。
<?php slot('title');?> MYPAGE <?php end_slot();?> <?php slot('sidemenu');?> <?php include_partial("global/menu", array('now' => 'member_add'));?> <?php end_slot();?>
mypageのaction。
public function executeIndex() { $this->getUser() -> getAttribute('member_id', NULL,sfConfig::get('sf_session_name')); $this->member = MemberPeer::retrieveByPK($member_id); //$this->comments = CommentPeer::retrieveByComment_Id($cooment_id) return sfView::SUCCESS; }奇跡といいたい。
でけた。
ていうか現状ではlogoutがbackendしかないからmypageでログアウトするのって
ログインしなおすんだよね・・・・・・権限で判定??
補足設定
backendのsettings.ymlを下記に変更。
#認証できない時はloginページに遷移 login_module: default # To be called when a non-authenticated user login_action: login # Tries to access a secure page #管理者権限が無い場合はエラー表示 secure_module: default # To be called when a user doesn't have secure_action: secure # The credentials required for an actionsessionの有効期限はsettings.ymlの95行目
# timeout: 1800 # Session timeout, in seconds
だよー。
来週は自分のプロフィールや投稿のみ編集可能にする。
とバリデートするそーな。
自分的お勧め
PHPエラーの意味を教えてくれるところ
2011年4月7日木曜日
4/7覚書
腰痛で火曜休み、今日は歯医者で遅刻。
4時間目
1.返信するの横に詳細を見るのリンク追加。
ALTER TABLE comment ADD access_cnt int;
4.詳細ページを開くごとにアクセス数に+1させて、
shared/access_cntコンポーネントで、アクセス数多い順のコメント5件表示
午前中にreply_cntでやったところらしい。
CommentPeer
action
5時間目上記答え合わせ。
6時間目
exerciseモジュール作成。indexからstage2へgetとpostの処理を再度勉強。
自信が無い人はstage10ぐらいまでgetとpostで送り続けるのをやろう。
これができないと今後ついていけなくなるそうです。
4時間目
1.返信するの横に詳細を見るのリンク追加。
<?php echo link_to("詳細を見る", "@commentdatail?id=".$comment->getId())?>2.default/datailでコメント詳細ページ表示
action側 public function executeDatail() { //GETで渡されてくるコメントIDとか $id = $this->getRequestParameter("id"); $this->comment = CommentPeer::retrieveByPK($id); $this->photo = $this->getRequestParameter("photo"); return sfView::SUCCESS; } datilSussess.php <div class="box"> <?php echo $comment->getNickname();?>の投稿<br> <?php if($comment->getPhoto()):?><br> <?php echo image_tag("/images/comment/".$comment->getPhoto());?><br><br> <?php endif;?> <?php if($comment->getPhoto2()):?><br> <?php echo image_tag("/images/comments2/".$comment->getPhoto2());?><br><br> <?php endif;?> <?php echo $comment->getContent();?><br> <?php echo $comment->getCreatedAt();?><br> </div>3.commentテーブルにaccess_cntカラム追加
ALTER TABLE comment ADD access_cnt int;
4.詳細ページを開くごとにアクセス数に+1させて、
shared/access_cntコンポーネントで、アクセス数多い順のコメント5件表示
午前中にreply_cntでやったところらしい。
CommentPeer
static public function retrieveAccessRanking() { $c = new Criteria(); $c->addDescendingOrderByColumn(self::ACCESS_CNT); $c->setlimit(5); return self::doSelect($c); }
action
public function executeDatail() { //GETで渡されてくるコメントID $id = $this->getRequestParameter("id"); $this->comment = CommentPeer::retrieveByPK($id); $this->photo = $this->getRequestParameter("photo"); //現在のアクセスカウントを取得 $access_cnt = $this->comment->getAccessCnt(); //取得したアクセスカウントに+1をセット $this->comment->setAccessCnt($access_cnt + 1); //更新 $this->comment->save(); return sfView::SUCCESS; }
5時間目上記答え合わせ。
6時間目
exerciseモジュール作成。indexからstage2へgetとpostの処理を再度勉強。
自信が無い人はstage10ぐらいまでgetとpostで送り続けるのをやろう。
これができないと今後ついていけなくなるそうです。
2011年4月4日月曜日
4/4覚書
1時間目~2時間目
☆複数画像UPとヘルパー
できてる人はアンケート
enquete_add
名前
性別(ラジオボタン)
興味のあること(チェックボックス)
コメント
画像
SQL
CREATE TABLE enquete(
id int not null auto_increment,
name text,
gender int,
hobby int ,
content text,
photo text,
created_at datetime,
primary key(id) );
ここで時間切れ。自習だぬー。
3時間目
☆ルーティング
ルーティングとは、URL マッピングとも呼ばれ、URLから判断して
使用するmoduleを決定する仕組み。
アクセスした時点でどこに飛ばすか、のコントロール機能。
場所はプロジェクト/apps/アプリケーション名/config/routing.yml
ルーティング名称(自由):
url: URL
param: {module: モジュール名, action: アクション名}
※default_symfonyの項目は保留
※URLに*でワイルドカード指定おk
ニュースモジュール作成とsymfony cc
symfony init-module front news
return sfView::SUCCESS;
/news/listにURLを変えるとほかページのリンク修正がめんどい。
そのときにルーティングで処理すると一括でできる。
デフォルトのURLを変更したいときにルーティングを使う。必要なければ使わなくてよい。
※入力ルールparamでは:の後、半角スペース必須。
つけたいルーティングは# default rules(ここから下削除不可)の上に置く。
実例
表示しないルールをつけることもできる。
IDの受け取り
コントローラー側
http://www.shonanbbs.com/news/datail/1111とか入れると数字が出てくるよ
@ルーティング名にするとそのルーティング名に則ったURLにできる。
値はGETで示す。
newsモジュールに以下記述
4時間目
部品化
パーシャル
一番簡単な部品化の方法で、主にロジックを含まないテンプレートを部品化する際に使用する。
指定したモジュール名/templatesディレクトリに、_テンプレート名.phpというファイルを作成する。
読み込むコード
実例
layout.phpの<div id="contentRight">直下に記述。
モジュール名にglobalにすると一番上のモジュールを指定できる。
templates直下に\menu.php作成し、
MENU
会員登録
とかを切り取って貼り付け。
◆練習問題
ヘッダーとフッターをpartial化
◆練習問題
sharedモジュール作成、templateはmessageでお知らせ文作成
member_addとか無いからlayoutにはっつけちゃったYO。
☆スロット
templateからlayoutを操作したい場合に利用
◆練習。
5時間目
◆練習問題 パンくずを実装
◆補足。関数利用可能
◆スロットとパーシャルの組み合わせ
6時間目
◆練習もっかいパーシャル。
☆コンポーネント
パーシャルにロジックが加わったものがコンポーネント。
部品化したいが、その部品を作成するためにはデータベースからデータを取得する
必要がある場合に使用される。
◆練習問題
member_listモジュール無い人は追加
sidemenuにmemberlistを出してみよう。
◆練習問題
最新のコメント5件をsidemenuに出してみよう。
あと_menuの各項目に<div class="sidelist">つけてねー。
今日は何とかついてこれた~~~~。ふぅ。
んで追加のCSS。適宜応用よろ。
☆複数画像UPとヘルパー
できてる人はアンケート
enquete_add
名前
性別(ラジオボタン)
興味のあること(チェックボックス)
コメント
画像
SQL
CREATE TABLE enquete(
id int not null auto_increment,
name text,
gender int,
hobby int ,
content text,
photo text,
created_at datetime,
primary key(id) );
ここで時間切れ。自習だぬー。
3時間目
☆ルーティング
ルーティングとは、URL マッピングとも呼ばれ、URLから判断して
使用するmoduleを決定する仕組み。
アクセスした時点でどこに飛ばすか、のコントロール機能。
場所はプロジェクト/apps/アプリケーション名/config/routing.yml
ルーティング名称(自由):
url: URL
param: {module: モジュール名, action: アクション名}
※default_symfonyの項目は保留
※URLに*でワイルドカード指定おk
ニュースモジュール作成とsymfony cc
symfony init-module front news
return sfView::SUCCESS;
/news/listにURLを変えるとほかページのリンク修正がめんどい。
そのときにルーティングで処理すると一括でできる。
デフォルトのURLを変更したいときにルーティングを使う。必要なければ使わなくてよい。
※入力ルールparamでは:の後、半角スペース必須。
つけたいルーティングは# default rules(ここから下削除不可)の上に置く。
実例
#news/listにURL変更。ルーティングルールは上位ほど強くなる。 newslist: url: /news/list param: { module: news, action: index }※routing.yml変更後は必ずsymfony cc
表示しないルールをつけることもできる。
newslist: url: /news param: { action: error404 }
IDの受け取り
コントローラー側
public function executeDatail() { print $id = $this->getRequestParameter("id"); //$this->id = $this->getRequestParameter("id"); return sfView::SUCCESS; }routing.yml側
newsdatail: url: /news/datail/:id param: { module: news, action: datail }http://www.shonanbbs.com/news/datail/33とか
http://www.shonanbbs.com/news/datail/1111とか入れると数字が出てくるよ
@ルーティング名にするとそのルーティング名に則ったURLにできる。
値はGETで示す。
newsモジュールに以下記述
4時間目
部品化
パーシャル
一番簡単な部品化の方法で、主にロジックを含まないテンプレートを部品化する際に使用する。
指定したモジュール名/templatesディレクトリに、_テンプレート名.phpというファイルを作成する。
読み込むコード
実例
layout.phpの<div id="contentRight">直下に記述。
モジュール名にglobalにすると一番上のモジュールを指定できる。
templates直下に\menu.php作成し、
MENU
会員登録
とかを切り取って貼り付け。
◆練習問題
ヘッダーとフッターをpartial化
◆練習問題
sharedモジュール作成、templateはmessageでお知らせ文作成
<?php include_partial("shared/message");?> _message.php <div style="boader: 2px; padding: 10px; background-color:#DF8713; margin:10px 0px;"> 管理者からの大切なお知らせ。 こちらをごらんください。 </div>
member_addとか無いからlayoutにはっつけちゃったYO。
☆スロット
templateからlayoutを操作したい場合に利用
◆練習。
layoutでtemplate作成。 <div id="pankuzu"> <?php include_slot("pankuzu");?> </div> indexSuccessでインクルード。 <?php slot('pankuzu');?> HOME <?php end_slot();?>
5時間目
◆練習問題 パンくずを実装
ヘルパー練習ページでも適用できるよ <?php slot('pankuzu');?> <?php echo link_to("HOME","/member/list")?>>ヘルパーの練習 <?php end_slot();?> CSS #pankuzu { boder-bottom:1px dotted #ddd; padding-bottom:5px; }◆練習問題 タイトルを変えてみよう
layout.phpの<?php include_title() ?>を <title><?php include_slot("title") ?></title>に変える indexSuccessはこう <?php slot('title');?> TOP | SHONANBBS <?php end_slot();?>
◆補足。関数利用可能
titleというスロットがあればtemplateを読み込むifが使える。 <title><?php if(has_slot("title")):?> <?php include_slot("title") ?> | <?php endif;?> SHONANBBS</title> templateがより省略できる <?php slot('title');?> TOP <?php end_slot();?>
◆スロットとパーシャルの組み合わせ
layoutのパーシャル切り取り、以下に変更 <?php include_slot("sidemenu");?> <?php slot('sidemenu');?> <?php include_partial("global/menu", array('now' => 'top'));?> <?php end_slot();?> ヘルパーページ <?php slot('sidemenu');?> <?php include_partial("global/menu", array('now' => 'help'));?> <?php end_slot();?> _menu.php <?php if ($now == "top"):?> <a href="/" class="nowpage">TOP</a><br> <?php else :?> <a href="/">TOP</a><br> <?php endif;?> <?php if ($now == "help"):?> <a href="/default/help" class="nowpage">ヘルパーの使い方</a><br> <?php else :?> <a href="/default/help">ヘルパーの使い方</a><br> <?php endif;?>
6時間目
◆練習もっかいパーシャル。
<?php include_partial("global/ad");?> <div class="ad"> 広告です。 </div>
☆コンポーネント
パーシャルにロジックが加わったものがコンポーネント。
部品化したいが、その部品を作成するためにはデータベースからデータを取得する
必要がある場合に使用される。
◆練習問題
member_listモジュール無い人は追加
sidemenuにmemberlistを出してみよう。
bbs2/apps/front/modules/shared/templatesに_memberlist.php作成 メンバー一覧 <?php foreach ($members as $member):?> <div class="sidelist"> <?php echo $member->getNickname();?> </div> <?php endforeach;?> bbs2/apps/front/modules/shared/actionsにcomponents.class.php作成 <?php class SharedComponents extends sfComponents { public function executeMemberlist(){ $c = new Criteria(); $this->members = MemberPeer::doselect($c); } }
◆練習問題
最新のコメント5件をsidemenuに出してみよう。
bbs2/apps/front/modules/shared/templatesに_newreplyt.php作成 最新の返信 <?php foreach ($replys as $reply):?> <div Class="sidelist"> <?php echo $reply->getContent();?> </div> <?php endforeach;?> bbs2/apps/front/modules/shared/actions/components.class.phpの memberlistの直下に作成 public function executeNewreply(){ $c = new Criteria(); $c->addDescendingOrderByColumn(ReplyPeer::CREATED_AT); $c->setlimit(5); $this->replys = ReplyPeer::doselect($c); }
あと_menuの各項目に<div class="sidelist">つけてねー。
今日は何とかついてこれた~~~~。ふぅ。
んで追加のCSS。適宜応用よろ。
#pankuzu { boder-bottom:1px dotted #ddd; padding-bottom:5px; } .nowpage { background-color:#FAB6D6; padding:1px; margin-bottom:1px; } .ad { border:1px solid #ddd; padding:10px; background-color:#D1DEE0; } .sidelist { border-bottom:1px solid #ddd; padding:5px 0px; }
4/1覚書
1時間目
replyに画像追加の続き。
ex.複数画像の続き
2時間目も同様
3時間目
☆ヘルパー
no_script_nameをONにすることでフロントコントローラーがURLに出なくなる。
4時間目
ヘルパー続き
5時間目
ヘルパーをbbs2に適用
6時間目
schema実行後に生成されるomディレクトリの子クラスに変更点を記述。
親クラスには記述しない。
来週はreply以外のデータ参照もあるそうな。
現時点ソース。カテゴリ未完成だよー;
写真複数にするときはphotoカラム追加と
/web/images/comment2とか複数必要だよー。
replyに画像追加の続き。
ex.複数画像の続き
2時間目も同様
3時間目
☆ヘルパー
no_script_nameをONにすることでフロントコントローラーがURLに出なくなる。
4時間目
ヘルパー続き
5時間目
ヘルパーをbbs2に適用
6時間目
schema実行後に生成されるomディレクトリの子クラスに変更点を記述。
親クラスには記述しない。
来週はreply以外のデータ参照もあるそうな。
現時点ソース。カテゴリ未完成だよー;
写真複数にするときはphotoカラム追加と
/web/images/comment2とか複数必要だよー。
コントロール側 public function executeIndex() { print_r(sfConfig::get('sf_support_mail')); //commentテーブル全行表示降順 //昇順 ->addAscendingOrderByColumn(column); $c = new Criteria(); $c->addDescendingOrderByColumn(CommentPeer::CREATED_AT); $this->comments = CommentPeer::doSelect($c); return sfView::SUCCESS; } public function executeConfirm() { $this->name = $this->getRequestParameter("name"); $this->coment = $this->getRequestParameter("coment"); $this->categorie = $this->getRequestParameter("categorie"); $photo1 = $this->getRequest()->getFile('photo1'); $photo2 = $this->getRequest()->getFile('photo2'); // sleepさせてrootで/tmpを見る //sleep(10); //画像の一時ファイル判定 if($photo1["tmp_name"] != '') { //保存する画像名はセッションID生成し付与 session_regenerate_id(); //myUtil::getFileExtで拡張子判別。帰り値は._gif._png._jpg $tmpname1 = 'photo1_' . session_id() .myUtil::getFileExt( $photo1["tmp_name"] ); //web/uploads/tmpへ画像を移動する $this->getRequest()->moveFile('photo1',sfConfig::get('sf_upload_dir').'/tmp/'.$tmpname1); //templateにパスを渡している $this->photo1 = $tmpname1; } //画像の一時ファイル判定 if($photo2["tmp_name"] != '') { //保存する画像名はセッションID生成し付与 session_regenerate_id(); //myUtil::getFileExtで拡張子判別。帰り値は._gif._png._jpg $tmpname2 = 'photo2_' . session_id() .myUtil::getFileExt( $photo2["tmp_name"] ); //web/uploads/tmpへ画像を移動する $this->getRequest()->moveFile('photo2',sfConfig::get('sf_upload_dir'). '/tmp/'.$tmpname2); //templateにパスを渡している $this->photo2 = $tmpname2; } return sfView::SUCCESS; } public function executeHelp() { return sfView::SUCCESS; } public function executeResult() { //nameとmailを変数にして渡す。 $name = $this->getRequestParameter("name"); $coment = $this->getRequestParameter("coment"); $categorie = $this->getRequestParameter("categorie"); //insertのmember //インスタンス化。空のオブジェクトを生成。 $comment = new Comment(); //変数にした名前とメールを入力。idカラムは自動なので不要。 //カラムにcreated_at、update_atがあればSymfonyが自動で一緒にやってくれる。 $comment->setNickname("$name"); $comment->setContent("$coment"); $comment->setCategorie("$categorie"); //insert文発行 $comment->save(); //画像データを変数にして渡す $photo1 = $this->getRequestParameter('photo1'); $photo2 = $this->getRequestParameter('photo2'); //画像の存在判定 if($photo1 != '') { ///uploads/tmp/'.$photo1から画像を取得 $src = sfConfig::get('sf_web_dir').'/uploads/tmp/'.$photo1; //最新(投稿と同一)のidを取得(autoincrement稼動時) $saveName = $comment->getId().myUtil::getFileExt($src); //TEMPから/images/comment/".$saveNameへ保存 $dst = sfConfig::get('sf_web_dir')."/images/comment/".$saveName; rename($src, $dst); $comment->setPhoto($saveName); $comment->save(); } if($photo2 != '') { ///uploads/tmp/'.$photo2から画像を取得 $src = sfConfig::get('sf_web_dir').'/uploads/tmp/'.$photo2; //最新(投稿と同一)のidを取得(autoincrement稼動時) $saveName = $comment->getId().myUtil::getFileExt($src); //TEMPから/images/comment/".$saveNameへ保存 $dst = sfConfig::get('sf_web_dir')."/images/comments2/".$saveName; rename($src, $dst); $comment->setPhoto2($saveName); $comment->save(); } return sfView::SUCCESS; }
index <div class="line"> <?php echo form_tag("default/confirm","method=post multipart=true")?> 新規投稿<br> <?php echo textarea_tag("coment", array("rows" => "10", "cols" => "30")) ?> <br> ニックネーム<?php echo input_tag("name", array("size => 20"))?> カテゴリ <?php $categorie = sfConfig::get('sf_categorie')?> <?php echo select_tag("$categorie", options_for_select($categorie,$value));?><br> 画像1<?php echo input_file_tag("photo1") ?><br> 画像2<?php echo input_file_tag("photo2") ?><br> <?php echo submit_tag("送信する") ?><br> </form> </div> <div class="comment"> <?php foreach ($comments as $comment):?> <?php echo $comment->getNickname();?>の投稿 投稿日時<?php echo $comment->getCreatedat();?> カテゴリ:<?php echo $comment->getCategorie();?><br><br><br> <?php echo $comment->getContent();?><br><br> <?php if($comment->getPhoto()):?> <?php echo image_tag('/images/comment/' .$comment->getPhoto(),"class=imgmain") ?><br><br> <?php endif;?> <?php if($comment->getPhoto2()):?> <?php echo image_tag('/images/comment/' .$comment->getPhoto2(),"class=imgmain") ?><br><br> <?php endif;?> <?php echo link_to("返信", "/reply_add/input", array("query_string" => "id=".$comment->getId()))?> <br><br> <?php $replys = $comment->getReplys();?> <?php foreach ($replys as $reply):?> <div class="reply"> <?php echo $reply->getNickname();?>さんの投稿 返信日時<?php echo $reply->getCreatedat();?><br><br> <?php echo $reply->getContent();?><br><br> <?php if($reply->getPhoto()):?> <?php echo image_tag('/images/reply/'.$reply->getPhoto(),"class=imgmain") ?><br><br> <?php endif;?> </div> <?php endforeach;?> <?php endforeach;?> </div>
input このコメントに返信します <div> <?php echo $comment->getContent();?><br> <?php if($comment->getPhoto()):?><br> <img src="/images/comment/<?php echo $comment->getPhoto();?>"><br><br> <?php endif;?> </div> <div class="line"> </div> 返信フォーム<br> <?php echo form_tag("/reply_add/confirm", "method=post multipart=true")?> <?php echo textarea_tag("coment", array("rows" => "10", "cols" => "30")) ?><br> ニックネーム<?php echo input_tag("name", array("size => 20"))?><br> <br> 画像1<?php echo input_file_tag("photo") ?><br><br> <?php echo input_hidden_tag('id', $comment->getId()) ?> <?php echo submit_tag("確認する") ?> </form>
confirm <?php echo form_tag("/reply_add/result", "method=post multipart=true")?> 返信内容<br> <?php echo $coment;?> <?php echo input_hidden_tag('coment', $coment) ?> <br> ニックネーム<br> <?php echo $name;?> <br> 画像<br> <?php if($photo !=""):?> <img src="/uploads/tmp/<?php echo $photo?>"> <br><br> <div class="line"></div> <?php echo input_hidden_tag('photo', $photo) ?> <?php endif;?> <?php echo input_hidden_tag('name', $name) ?> <?php echo input_hidden_tag('id', $id) ?> <br> <?php echo submit_tag("完了") ?> </form>
登録:
投稿 (Atom)