ラベル 講座 の投稿を表示しています。 すべての投稿を表示
ラベル 講座 の投稿を表示しています。 すべての投稿を表示

2011年4月28日木曜日

4/28覚書

しのさん協力■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>
を追加

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

書きかけ
if(!$member){
$this->redirect('testmember_list/index')
}
<a href="/testmember_list/index?delete=on&id=<?php echo $item->getId()?>">
<a onclick="return confirm('削除しますか?');" href=

2011年4月25日月曜日

4/25覚書

色々あってかなり間が空いた。その色々は主に金銭面だが。

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.各モジュールページ遷移図

で、こんなのできた。

自宅でやります・・・・・・。

テーブル名とカラム名は同じにしないって一言が・・・・・・あれ? 似たようなことを前に聞いた気がする。

2011年4月11日月曜日

4/11覚書

1時間目自習
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
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 action
sessionの有効期限はsettings.ymlの95行目
# timeout: 1800 # Session timeout, in seconds
だよー。

来週は自分のプロフィールや投稿のみ編集可能にする。
とバリデートするそーな。

自分的お勧め
PHPエラーの意味を教えてくれるところ

2011年4月7日木曜日

4/7覚書

腰痛で火曜休み、今日は歯医者で遅刻。

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(ここから下削除不可)の上に置く。

実例
#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とか複数必要だよー。

コントロール側

 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>

2011年3月31日木曜日

3/31覚書

1時間目

reply_add実装続き

2時間目

reply_add実装

idを引き継ぐ処理以外は基本おなじなのだねー。

ていうかそのreplyを表示させるのががが。

3時間目
画像アップロード

[name] => notice01.jpg
[type] => image/jpeg
[tmp_name] => /tmp/phpyCW55n
[error] => 0
[size] => 83218

ファイル送信時次のプログラムの処理が終わるまでの間、
サーバーのTEMPディレクトリに一時保管されている。

sleep(20);を加えると20秒間処理を止めるので、
その間にPuTTYからrootで入ってcd /tmpで中身を見ると、
-rw------- 1 apache apache 83218 3月 25 16:25 phpJNeLpc
ってファイルがsleepで設定した時間分だけ確認できる。
処理が終われば消える。

4時間目

画像アップロード処理続き
TEMPディレクトリ作成とパーミッション変更

cd web/uploads
mkdir tmp
chmod -R 777 tmp


画像のアップロード
実際に表示させてみる


5時間目
photoカラム追加
ALTER TABLE comment ADD photo text;
schema.yml、model作成
/web/images/commentディレクトリ作成
chmod 777 commentでパーミッション作成

あと画像表示
できたらpreplyも。
replyカラム+/web/images/replyカラムつけてね。

6時間目

あと画像表示
できたらpreplyも
作業続き

めんどいからここでコード。
action.class.php
<?php

class reply_addActions extends sfActions
{
  public function executeConfirm()
  {
   $this->id = $this->getRequestParameter("id");
 $this->name = $this->getRequestParameter("name");
 $this->coment = $this->getRequestParameter("coment");
 $photo = $this->getRequest()->getFile('photo');

   if($photo["tmp_name"] != '') {

  //保存する画像名はセッションID生成し付与
  session_regenerate_id();
  //myUtil::getFileExtで拡張子判別。帰り値は._gif._png._jpg
  $tmpname = 'photo_' . session_id() .myUtil::getFileExt( $photo["tmp_name"] );
  //web/uploads/tmpへ画像を移動する
  $this->getRequest()->moveFile('photo',sfConfig::get('sf_upload_dir').'/tmp/'.$tmpname);

  //templateにパスを渡している
  $this->photo = $tmpname;
 }

 return sfView::SUCCESS;
  }

  public function executeInput()
  {
   //GETで渡されてくるコメントID
   $id = $this->getRequestParameter("id");
   $this->comment = CommentPeer::retrieveByPK($id);
   $this->photo = $this->getRequestParameter("photo");


 return sfView::SUCCESS;
  }

  public function executeResult()
  {
 //idとnameとmailを変数にして渡す。
 $id = $this->getRequestParameter("id");
 $name = $this->getRequestParameter("name");
 $coment = $this->getRequestParameter("coment");

 //replyのupdate
 //インスタンス化。空のオブジェクトを生成。
 $reply = new Reply();
 //変数にした名前とメールを入力。
 $reply->setCommentid("$id");
 $reply->setNickname("$name");
 $reply->setContent("$coment");
 //insert文発行
 $reply->save();

 $photo = $this->getRequestParameter('photo');

  //画像の存在判定
  if($photo != '') {

   ///uploads/tmp/'.$photoから画像を取得
   $src = sfConfig::get('sf_web_dir').'/uploads/tmp/'.$photo;
   //最新(投稿と同一)のidを取得(autoincrement稼動時)
   $saveName = $reply->getId().myUtil::getFileExt($src);
   //TEMPから/images/comment/".$saveNameへ保存
   $dst = sfConfig::get('sf_web_dir')."/images/reply/".$saveName;

   rename($src, $dst);
   $reply->setPhoto($saveName);
   $reply->save();

  }

   return sfView::SUCCESS;
  }
}

inputSuccess.php
このコメントに返信します
<div>
<?php echo $comment->getContent();?>
  <?php if($comment->getPhoto()):?>
  <img src="/images/comment/<?php echo $comment->getPhoto();?>"><br><br>
  <?php endif;?>
</div>

<div class="line">
</div>
返信フォーム<br>

<form action="/reply_add/confirm" method="post" enctype="multipart/form-data">
<textarea name="coment"></textarea><br>
ニックネーム<input type="text" name="name" size="20">
<br>
<input type="file" name="photo"><br>
<input type="hidden" name="id" value="<?php echo $comment->getId();?>">
<input type="submit" value="確認する">
</form>
confirmSuccess.php
<form action="/reply_add/result" method="post">
返信内容<br>
<?php echo $coment;?>
<input type="hidden" name="coment" value="<?php echo $coment;?>">
<br>
ニックネーム<br>
<?php echo $name;?>
<br>
画像<br>
<?php if($photo !=""):?>
<img src="/uploads/tmp/<?php echo $photo?>">
<br><br>
<div class="line"></div>

<input type="hidden" name="photo" value="<?php echo $photo;?>">
<?php endif;?>
<input type="hidden" name="name" value="<?php echo $name;?>">
<input type="hidden" name="id" value="<?php echo $id;?>">
<br>

<input type="submit" value="確認する">
</form>

resultSuccess.php
完了しました。
<a href="/">トップに戻る</a>

パーミッション解説
自分とグループと他人に対してのアクセス権限。
ファイルへの読み(read) 書き(write) 実行(execute)についての権限を与えること。

できる人だけ。
アップロード3つぐらい送って見る。
複数の条件がどーしても思い浮かばない・・・
$photoをどこで複数化するんだああああ。

おまけ
ntpやってなかったので設定。
教科書のサーバー構築の一番下にあるntp設定やればいいよ。
あとcreated_atの表示で詰まった。
_含むばあいは_取っていいみたい。
例】
投稿日時getCreatedat();?>

2011年3月29日火曜日

3/29覚書

1時間目
DBstudyにcontactテーブルを追加
create table contact (
id int not null auto_increment,
name text,
cotent text,
created_at datetime,
primary key(id)
);
※primary key(id)が最初抜けててエラーググって判明;
あぶねー。

schema作成
symfony propel-build-schema
model作成
symfony propel-build-model

lib/modelに
contact.phpとcontactPeer.phpができているか確認。

2時間目

insert復習

actions.class.php
  //insertのcontact。
  //インスタンス化。空のオブジェクトを生成。
  $contact = new Contact();
  //名前と内容を入力。
  $contact->setName('ゆっきー');
  $contact->setCotent('今日はなんとなくやれるかな');
  //insert文発行
  $contact->save();
indexSuccess.php
<div class="tblData">

<table>
 <tr>
  <th>名前</th>
  <th>内容</th>
 </tr>
 <?php foreach ($contacts as $contact):?>
 <tr>
  <td><?php echo $contact->getName();?></td>
  <td><?php echo $contact->getCotent();?></td>
 </tr>
 <?php endforeach;?>
</table>

</div>

updateは省略。
1行削除も省略。
  //全行削除
  $c = new Critreria;
  $contacts = ContentPeer::doselect($c);
  foreach($contacts as $contact){
   $contact->delete();
  }

☆練習問題
contact_addモジュール作成してinsert、confirm、result作成。

3時間目
☆練習問題
contact_addに下記追加。
性別 男性 女性 ラジオボタン
都道府県 prefで
興味のあること チェックボックス

4時間目

もっかいbbs2バックアップしてつくり直し。
んで掲示板reply_addつける。
indexで新規投稿と投稿一覧、各投稿に返信リンク、
新規投稿→confirmで確認→resultで完了
返信リンクid渡し→入力画面id渡し→confirmで確認id渡し→resultで完了

create table reply (
id int not null auto_increment,
comment_id int,
nickname text,
content text,
created_at datetime,
primary key(id)
);

symfony init-module front reply_add
symfony propel-build-schema
symfony propel-build-model
symfony cc
忘れないようにねー

シンボリックリンク
webでln -s /usr/share/pear/data/symfony/web/sf ./sf

ラストまで。

返信の表示処理は明日。
不完全なのでコードは明日。

2011年3月28日月曜日

3/28覚書

1時間目

☆modelによるCRUD(クラッド)
以下の4つの機能を使う。
◆Create
◆Update
◆Delete
◆Read←昨日からやってるデータの呼び出し

◆Create
action側
  //insertのcomment。
  //インスタンス化。空のオブジェクトを生成。
  $comment = new Comment();
  //名前と内容を入力。
  $comment->setNickname('satou');
  $comment->setContent('今日はいい天気');
  //insert文発行
  $comment->save();

  //insertのmember
  //インスタンス化。空のオブジェクトを生成。
  //$member = new Member();
  //名前とメールを入力。idカラムは自動なので不要。
 //カラムにcreated_at、update_atがあればSymfonyが自動で一緒にやってくれる。
  //$member->setNickname("ooyama");
  //$member->setMailaddress("ooyama@sample.com");
  //insert文発行
  //$member->save();

  //最初に必ずセット select * from member;と同じ。
  $c = new Criteria();

View側commentテーブル

<div class="tblData">
<table>
 <tr>
  <th>名前</th>
  <th>内容</th>
 </tr>
 <?php foreach ($comments as $comment):?>
 <tr>
  <td><?php echo $comment->getNickname();?></td>
  <td><?php echo $comment->getContent();?></td>
 </tr>
 <?php endforeach;?>
</table>

</div>

  //$comment+sで複数にする。commentテーブルのすべてのデータを引き出す。
  $this->comments = CommentPeer::doSelect($c);

2時間目
◆Update
Createとの差異は空のオブジェクト生成をしないことだけ。
$member = MemberPeer::retriveByPK();を使う点のみ。
//Update
  $member = MemberPeer::retrieveByPK(5);
  //名前とメールを入力。
  $member->setNickname("ooyama");
  $member->setMailaddress("ooyama@sample.com");
  //insert文発行
  $member->save();

◆Delete
//Delete
  $member = MemberPeer::retrieveByPk(7);
  //memberがあれば削除。こうしないとエラーになる。
  if($member){
   $member->delete();
  }

☆練習問題
1.bbs2でmember_addモジュール作成
2.input、confirm、resultのaction作成
3.resultでinsert処理

1~2は3/23覚書を参考に~。


3時間目
☆練習問題答え合わせ

public function executeConfirm()
  {
 $this->name = $this->getRequestParameter("name");
 $this->mail = $this->getRequestParameter("mail");
   return sfView::SUCCESS;
  }
  public function executeInput()
  {
   return sfView::SUCCESS;
  }
  public function executeResult()
  {
   //insertのmember
 //インスタンス化。空のオブジェクトを生成。
 $member = new Member();
 
 //nameとmailを変数にして渡す。
 $name = $this->getRequestParameter("name");
 $mail = $this->getRequestParameter("mail");

 //insertのmember
 //インスタンス化。空のオブジェクトを生成。
 $member = new Member();
 //変数にした名前とメールを入力。
 $member->setNickname("$name");
 $member->setMailaddress("$mail");
 //insert文発行
 $member->save();

   return sfView::SUCCESS;
  }

4時間目
1.bbs2でmember_list、member_editモジュール作成。
2.モジュール作成。一覧表に編集ページリンクつけて、idを渡す。
3.余裕のある人はdeleteで削除処理

5時間目

作成続き

6時間目
ううむidのReadがどうしても理解できなかった・・・・・・。member_addはさくっとできたのに(つД`)
自力でできなかった人は/bbs2/apps/front/modules/に移動してから、
mv member_list bk.member_list
mv member_edit bk.member_edit
でバックアップとっても一回やろう。

public function executeConfirm()
  {
   //IDを受け取る
 $this->id = $this->getRequestParameter("id");
 //名前、メールアドレスを受け取る
 $this->name = $this->getRequestParameter("name");
 $this->mail = $this->getRequestParameter("mail");


 return sfView::SUCCESS;
  }
  public function executeInput()
  {

   //IDを受け取る
 $id = $this->getRequestParameter("id");
 $this->member = MemberPeer::retrieveByPK($id);
 //名前、メールアドレスを受け取る(オブジェクトごと受け取るときは無しでよい)
 $this->name = $this->getRequestParameter("name");
 $this->mail = $this->getRequestParameter("mail");

 return sfView::SUCCESS;
  }
  public function executeResult()
  {
   //update-member
 //nameとmailを変数にして渡す。
 $name = $this->getRequestParameter("name");
 $mail = $this->getRequestParameter("mail");

 //IDを指定。
 $id = $this->getRequestParameter("id");
 $member = MemberPeer::retrieveByPK("$id");

 //変数にした名前とメールを入力。ここでIDは要らないよ。
 $member->setNickname("$name");
 $member->setMailaddress("$mail");
 //Update実行
 $member->save();

 return sfView::SUCCESS;
  }
insertSucces.php
<form action="/member_edit/confirm/" method="POST">
名前:<input type="text"name="name" value="<?php echo $member->getNickname();?>"><br>
メールアドレス:<input type="text"name="mail" size="30"
 value="<?php echo $member->getMailaddress();?>">

<br>
<input type="submit" name="send" value="確認">
<input type="hidden" name="id" value="<?php echo $member->getId();?>">
</form>
comfirmSucces.php
<form action="/member_edit/result/" method="POST">
名前:
<?php echo $name;?>
です。
<br>
<input type="hidden" name="name" value="<?php echo $name;?>">
メールアドレス:
<?php echo $mail;?>
です。
<br>
<input type="hidden" name="mail" value="<?php echo $mail;?>">
<input type="hidden" name="id" value="<?php echo $id;?>">
<input type="submit" name="send" value="更新する">
</form>
resultSucces.php
完了しました。


おまけ
commentの検索
View側
<form action="/" method="POST">
名前:<input type="text" name="keyword2">
<input type="submit" name="send" value="送信"></form>

action側
  //シンプルなlike検索機能bycomment
  $d = new Criteria();
  $keyword2 = $this->getRequestParameter("keyword2");
  if($keyword2 !=""){
  $d->add(CommentPeer::NICKNAME, "%".$keyword2."%", Criteria::LIKE);
  }
  //$comment+sで複数にする。commentテーブルのすべてのデータを引き出す。
  $this->comments = CommentPeer::doSelect($d);

2011年3月25日金曜日

3/25覚書

1時間目は遅刻

やること
昨日の復習
1.bbs2をbk.bbs2にリネームしてバックアップ
mv bbs2 bk.bbs2
2.front backend mypage
各アプリケーション作成およびdefaultモジュール作成。
3.backendとmypageで/区切りのURLでアクセス
4.frontアプリケーションのレイアウトを変更。

2時間目

1時間目続き。
30分から復習

3時間目
mypageは出るがbackendが出ない。はて。
/bbs2/web/backend/backend.phpの
../../にiが入ってた_| ̄|○
直った。

ちなみにでらっちが/web/main.cssと/apps/front/templates/layout.phpの
中身メールでくれてるよ。昨日とおとといのおいらの記事にもあるけど。
でらっちのみてね~。

member_addはいいのかなあ・・・・・・。

4時間目
retrieveByPK(1);のKは基本

困ったときのデバッグとシンボリックリンク
http://www.shonanbbs.com/front_dev.php
画面が真っ白のときはここを見ればエラーが書いてある。

で、デバッグバーの画像がまだ引っ張れてないので関連付け
bbs2/webで下記実行
ln -s /usr/share/pear/data/symfony/web/sf ./sf

sf -> /usr/share/pear/data/symfony/web/sf
が出ていればデバッグページでF5で出てくるよ。

backendやmypageなどのほかのページには、各ディレクトリへ移動してから
各_dev.phpの../を2個にしておくよ。

ln -s ../sf sf
上の階層(web)からsfを引っ張ってくるよ。

CSSも同じスタイルでよければ
ln -s ../CSS CSS
でつくよ。

セキュリティ上非常に危険なため、リリース前には必ず_dev.phpは削除する。

5時間目
Criteria(クライテリア)による条件指定
WHEREの代わりに使う。

$c = new Criteria();

$c->add(テーブル名Peer::カラム大文字, 指定する値, 条件)
条件を書かない場合はカラム=値と等しい場合となる。
SQL文だとこうなるけど
select * from member whwre id =1;
Symfonyではこうなる

//最初に必ずセット select * from member;と同じ。
  $c = new Criteria();

  //IDが1のデータ
  //$c->add(MemberPeer::ID, 1);

  //member+sで複数にする。1行分のデータを引き出す。
  $members =MemberPeer::doSelectOne($c);

  //指定したIDのみ1行だけ引き出す。
  $member = MemberPeer::retrieveByPK(2);
  //$memberを表示させる。
  //print $member->getNickname();

  print_r ($members);

ソース出すとこうなる。データは配列で受け取る。
Member Object
(
    [id:protected] => 1
    [nickname:protected] => yamazaki
    [mailaddress:protected] => ****@gmail.com
    [password:protected] => 
    [created_at:protected] => 
    [alreadyInSave:protected] => 
    [alreadyInValidation:protected] => 
    [validationFailures:protected] => Array
        (
        )

    [_new:private] => 
    [_deleted:private] => 
    [modifiedColumns:protected] => Array
        (
        )

)

☆DBから名前のデータを引き出す。

action.class.php
  //最初に必ずセット select * from member;と同じ。
  $c = new Criteria();

  //$member+sで複数にする。テーブルのすべてのデータを引き出す。
  $this->members = MemberPeer::doSelect($c);

indexSuccess.php
{を使うとわかりにくいので、:<?php endforeach;?>で囲う。

<?php foreach ($members as $member):?>
<?php echo $member->getNickname();?><br>
<?php endforeach;?>

☆練習問題
名前とメールアドレスをテーブルに出力+CSSで整形

indexSuccessのソース

<div class="tblData">
<table>
 <tr>
  <th>名前</th>
  <th>メールアドレス</th>
 </tr>
 <?php foreach ($members as $member):?>
 <tr>
  <td><?php echo $member->getNickname();?></td>
  <td><?php echo $member->getMailaddress();?></td>
 </tr>
 <?php endforeach;?>
</table>
</div>

MAINCSS
.tblData table {
border-collapse:collapse;
font-size:93%;
margin:5px 0;
}
.tblData th {
background:none repeat scroll 0 0 #EEEEEE;
color:#333333;
font-weight:bold;
padding:5px;
width:120px;
}
.tblData th, .tblData td {
border:1px solid #ddd;
paddig: 5px 10px;
}


6時間目
☆Criteria(クライテリア)による条件指定

条件
Criteria::EQUAL
Criteria::NOT_EQUAL

//最初に必ずセット select * from member;と同じ。
  $c = new Criteria();

  //IDが1のデータ
  //$c->add(MemberPeer::ID, 1);

  //IDがyamazakiのデータ select * from member where nickname ;
  //$c->add(MemberPeer::NICKNAME, 'yamazaki', Criteria::NOT_EQUAL);

  //like指定
  //$c->add(MemberPeer::NICKNAME, "%yama%", Criteria::LIKE);

  //日付指定検索
  //$c->add(MemberPeer::CREATED_AT, "2011-03-01", Criteria::GREATER_THAN);

  //複数条件
  //$c1 = $c->getNewCriterion(MemberPeer::CREATED_AT, "2011-03-01", Criteria::GREATER_THAN);
  //$c2 = $c->getNewCriterion(MemberPeer::NICKNAME, "ya%", Criteria::LIKE);
  //$c1->addOr($c2);
  //$c->add($c2);

  //$member+sで複数にする。テーブルのすべてのデータを引き出す。
  $this->members = MemberPeer::doSelect($c);

忘れてたUPDATE
日付修正ID指定込み
update member set created_at ='2011-03-25' where id =2;
名前文字化け修正ID指定込み
update member set nickname =('名前') WHERE id =2;


☆練習問題 テーブルの上に検索欄追加。余裕のある人はcommentも呼び出して。
indexSuccess側
<form action="/" method="POST">
名前:<input type="text" name="keyword">
<input type="submit" name="send" value="送信"></form>

action側
  //最初に必ずセット select * from member;と同じ。
  $c = new Criteria();
  //シンプルなlike検索機能
  $keyword = $this->getRequestParameter("keyword");
  if($keyword !=""){
  $c->add(MemberPeer::NICKNAME, "%".$keyword."%", Criteria::LIKE);
  }

  //$member+sで複数にする。テーブルのすべてのデータを引き出す。
  $this->members = MemberPeer::doSelect($c);


commentに何も入れてなかった。サンプルに残そー。

insert into comment (nickname,content,created_at) values ('山崎','腰が痛い','2011-03-25');
insert into comment (nickname,content,created_at) values ('みっくみく','ボカロボカロ','2011-03-25');
insert into comment (nickname,content,created_at) values ('サンレッド','コードナンバー046','2011-03-25');
insert into comment (nickname,content,created_at) values ('ウサコッツ','アニマル怪人','2011-03-25');

2011年3月24日木曜日

3/24覚書

1時間目
腰痛&腹痛のため掃除はお休み。
・EclipceでShift+Ctrl+Fキーで勝手に整形してくれる。超便利。
(でも今までの感覚からするとちょっと見づらいかな;)
・☆練習問題解説編
user_addモジュールにinput、confirm、resultのactionを入れよう。
ページの内容は名前を入力→確認→完了の流れで作ろう。
できたらMENUの下に会員登録ってリンクつけてね。

ファイル自体が壊れたりエラーが多い時はPuTTYで削除かディレクトリごと

2時間目

・☆練習問題解説編続き
・メールアドレスの処理を追加
・bbs2にbackendアプリ追加
symfony init-app backend

frontは記事表示を担当。backendで管理機能を担当。
frontコントローラーのリクエストを受けるのはindex.php。
frontアプリケーションのfrontコントローラーはindex.php。

backendコントローラーのリクエストを受けるのはbackend.php。
backendアプリケーションのbackendコントローラーはbackend.php。

backendにdefaultmodule追加
bbs2で以下実行
symfony init-module backend default

2番目以降のURLは省略不可。
ブラウザでアクセスするときは
http://www.shonanbbs.com/backend.php/default/index
SEO的にまずいので/で簡略化だけど3時間目で。

3時間目

アプリ―コントローラーの関係

見栄えの問題やSEO上の考慮から
http://www.shonanbbs.com/backend/default
でアクセスできるように設定する。

1.cd /home/teacher/bbs2/web
に移動

2.backendディレクトリを作成
mkdir backend

3.backend.php backend_dev.phpをbackendディレクトリへ移動
mv backend.php backend_dev.php ./backend

4.htaccessディレクトリをbackendディレクトリへコピー
cp .htaccess ./backend

5.backendディレクトリへ移動
cd backend

6..htaccessの内容を変更する
vi .htaccess
RewriteBaseとRewriteRuleを以下のように変更

8行目
#RewriteBase /の#をとる
22行目
RewriteRule ^(.*)$ /backend/backend.php [QSA,L]
に変更する。

7.backend.phpを開いて下記に変更
3行目
define('SF_ROOT_DIR', realpath(dirname(__FILE__).'/../..'));
/..を1階層増やすだけ。

8.http://www.shonanbbs.com/backend/defaultでアクセスできることを確認。

☆練習問題
mypageアプリを新規追加してbackendと同じようになってみよう。

4時間目

☆練習問題
mypageアプリを新規追加してbackendと同じようになってみよう。

の答え合わせ。

☆YAML
ヘッダー情報はYAML、ymlファイルで管理。
/bbs2/apps/front/config/view.yml

metas:
title: SHONANBBS
に変更し、
symfony cc(CCはキャッシュクリア)
ymlを変更したら必ずsymfony ccを行い、F5でページ更新。

ここの詳しい話は後日。
5時間目
metasの内容を以下に変更。

description: 課題掲示板です。
keywords: WEBエンジニア養成科,php,Symfony
language: ja

変更したらsymfony ccを行い、F5でページ更新。

■出ないとき
キャッシュをクリアする権限をユーザーでなくrootですると、Symfony ccが正常終了しない。
bbs2で
chown -R ユーザー:ユーザー /cache
でキャッシュの権限をユーザーに変更しなおすか、

chown -R755 ユーザー:ユーザー /cache
+パーミッション変更やてみる。


個別に書きたいときは各metasの項目を削除しlayout.phpで直書きか後日行う部品化を使う。

CSSも stylesheets: [main]
標準のCSS正規パス /home/yamazaki/bbs2/web/css/main.cssに存在する。
書き足したいときはカンマ+スペースで区切る
stylesheets: [main, mypage, ・・・]

javascripts: []もある。今はいじらないけど。

has_layout: on

actionの出力結果をレイアウトしなくていいときはoffにできるよ。

layout: layout
layout.phpを使うという意味。名称変更可能。

☆データベース
SQL を使用せずにデータベースを操作する、O/Rマッピングを使う。

O/R マッピングとは、「オブジェクト」と「リレーショナルデータベース」を
マッピング(対応付け)することです。
O/R マッピングは実装時のデータベース操作にかかわる煩雑な作業を軽減してくれます。

SQLのデータの記述はルールが無いため複雑になりやすい。

O/Rマッピングはルールが決まっているので作業効率が上がる。

とりあえずrootでmysqlログインするよー

ログインしたらcreate database study;でDB作成。
show database;でstudyの存在を確認したら

GRANT ALL ON study.* TO ユーザー名@"localhost" IDENTIFIED BY "パスワード";
flush privileges;

ホスト名は同じサーバーならlocalhost、外部からならIPアドレス。

しかし・・・・・・なぜかflush privileges;ができない
ERROR 1146 (42S02): Table 'mysql.servers' doesn't exist
になってしまう。

回避策
use mysql;

を実行し下記コピペ。

CREATE TABLE `servers` (
`Server_name` char(64) NOT NULL,
`Host` char(64) NOT NULL,
`Db` char(64) NOT NULL,
`Username` char(64) NOT NULL,
`Password` char(64) NOT NULL,
`Port` int(4) DEFAULT NULL,
`Socket` char(64) DEFAULT NULL,
`Wrapper` char(64) NOT NULL,
`Owner` char(64) NOT NULL,
PRIMARY KEY (`Server_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='MySQL Foreign Servers table';

も一回flush privileges;でようやく完了。

6時間目
comment、member、テーブル作成。

create table comment (
id int not null auto_increment,
nickname text,
content text,
created_at datetime,
primary key(id)
);

create table member (
id int not null auto_increment,
nickname text,
mailaddress text,
password text,
created_at datetime,
primary key(id)
);

☆Symfonyでのデータベース接続
/bbs2/config/databases.yml
#をすべて取る。

mysql://root@localhost/dbnameを変更
mysql://ユーザー名:パスワード@localhost/study
エンコード設定とプログラムの記述注意点
YAMLは先頭部分の記述は半角スペース2個をひとつと判断している。
この部分の構成は崩さないように。

all:
  propel:
    class:          sfPropelDatabase
    param:
      dsn:          mysql://ユーザー名:パスワード@localhost/study
      encoding: utf8


/bbs2/config/propel.iniの以下を変更

propel.database.createUrl = mysql://root@localhost/
propel.database.url = mysql://root@localhost/bbs2


propel.database.createUrl = mysql://ユーザー名:パスワード@localhost
propel.database.url = mysql://ユーザー名:パスワード@localhost/study

☆schema.ymlを作成する(DB作成後のみ処理可能)
モデルを作成するための設計書にあたるschema.ymlを作成する。
DBを見に行って接続情報・テーブル情報を引き出し、データファイルを作るための設計書を作成。

一般ユーザーでbbs2から実行。
symfony propel-build-schema

vi /bbs2/config/schema.yml
で中身にcommentテーブルなどが出ている。

次にモデルファイルを作成。
bbs2で実行
symfony propel-build-model

cd lib/modelの中身にcommentPeer.phpとmemberPeer.phpができていればおk。

?? テーブル構造に変化があったらschemaとmodel再生成。
独自追加したい場合はschema.ymlとDB両方とも手書き修正。
自動生成させるとせっかく変えた設定が上書きされてしまう。

7時間目

データ入れます。
set names sjis;
忘れないでねー。

INSERT INTO member (nickname, mailaddress) VALUES
('yamazaki', 's****@gmail.com');
INSERT INTO member (nickname, mailaddress) VALUES
("みっくみく", "mmd@gmail.com");
INSERT INTO member (nickname, mailaddress) VALUES
("サンレッド", "sunred@gmail.com");
INSERT INTO member (nickname, mailaddress) VALUES
("ウサコッツ", "usako@gmail.com");

停電なんでここまで。

2011年3月8日火曜日

3/8覚書

1時間目
お掃除。
VMWAREとCentOSのインストール。
ファイルサイズがGB単位なのでUSBメモリでコピー。
っても待ち時間にVMWAREはDLした。
さすがにUSBが一個なので時間かかる・・・・・・。

2時間目
ファイルコピー終わらず・・・・・
USB2個あればなぁwwww

3時間目
vmware とは、クライアントのマシンに仮想サーバを構築するためのソフト。
開発現場でも、vmware で個人用開発環境を構築し、
そこで開発したプログラムを本番環境に移すという開発フローを取っている人が多い。

vmware playerのインストール
* vmware playerをダウンロードする
* ダウンロードしたVMware-player-3.1.2-301548.exeをクリックしインストールを開始する
* すべて「次へ」で最後にパソコンの再起動を行なう
* デスクトップに出来ているvmware player のショートカットをクリックし起動する。

次回からは起動してCent OS選択して仮想マシンの再生→PuTTYで実行。

CentOSのインストール

コピーしたCentOS-5.5-i386-bin-DVD.isoを
マイドキュメントに生成されたMy Virtual Machinesへドラッグ。
マウスカーソルの動作はCent OSかWindowsか切り替えが必要。
Cent OSから戻るときはCtrl+Altで抜ける。
サーバー管理者パスワードは6文字以上で設定。
細かい手順は訓練サイトみて。
☆POINT
【Desktop-Gnome】のチェック除外→Cent OSのデスクトップ画面を使わない。
つかサーバーなんだし要らないよ。重くなるし。現場環境に合わせるのだ。
【今すぐカスタマイズ】で選択し左メニューから【開発】、右のセレクトボックスで
【レガシーなソフトウェアの開発】と【開発ツール】、【開発ライブラリ】にチェック
これをしないとコンパイルの際にライブラリが無いといわれてしまう。

4時間目
rootでログイン。さっき決めたパスワード(非表示)を入力して
root@localhostが出たら成功。
ifconfigを入力してinet addrの192.168.~をメモ。
putty起動してホストにメモった192.168.~を入力。ポートはデフォルト22まま。
セッション接続名は任意だがVMWAREとでもつけて保存。
そして開き、またrootとパスワード(ここも非表示)

Cent OSはあまりいじらないが、
root(管理者)ユーザーのままだと危険なので別ユーザーを作る。

☆以降PuTTYで操作。
PuTTYでuseradd 半角ユーザー名。変化無ければ作成成功。
パスワードはpasswd ユーザー名で変更可能
パスワードを聞かれるので2回パスワードを入力する
exitでPuTTY終了。PuTTY再起動で設定したユーザー名とパスワードでログイン。

あとセッション切れ防止のための処理。
まずは設定したセッション選択して読み込み。


左側メニューの接続からkeepaliveの数値を300に変更して、
セッションを再度選択して保存。


☆文字化け時の対策はUTF-8(CJK)を選択。変換と同じ処理で保存オヌヌメ。

su(switch userコマンド)で追加したユーザになり、自分のルートディレクトリを表示する
ちなみに[ユーザー名@localhost~]$は一般ユーザー。
[ユーザー名@localhost~]#は管理者です。


ユーザー変更は
su ユーザー名で変更。suだけだとrootへスイッチ(ただし権限は元ユーザーのまま)。
ここからexitすると元のユーザーに戻る。
su -を実行するとスイッチ先のユーザーの権限(環境変数)へ移行できる。

【練習】
・ユーザーを新規追加。

5時間目

VI操作
UNIX 環境の標準テキストエディタ
特徴
* コマンドモードとテキスト入力モードがある。
* 独特なキー操作
* 軽い
他にemaxというエディタもあるが、VIが標準装備。
コマンド
pwd 自分のディレクトリ表示
ls -al自ディレクトリのファイル一覧を表示


vi test.textで作成。最初はコマンドモードなのでテキスト入力モードへ切り替え。
iキーで変更可能。ESCでコマンドモードに変わる。
保存はESC押してから:wq!で保存され、コマンドモードに戻る。小文字でコマンドと認識。
wq(Write & Quit)!(強制)
vi 既存ファイル名(拡張子必須)で既存ファイルが開ける。

6時間目
Hキー:左
Lキー:右
Kキー:上
Jキー:下

キーボードでカーソル移動。マウスが無かった時代に
ホームポジションでカーソル移動ができるようにした工夫。
文字がある箇所のみ→キーで次の行に移動できるが、
文字が続いていない場合はJキーで下げる必要がある。

文字挿入はESCでコマンドでカーソル移動、iキーで挿入、ESCでコマンド移動
おまけに行が続くとJキー/Kキーで下の行えらべねええええええ。

コピー&ペースト
コピーしたい箇所を選択するだけでコピーされ、右クリックで貼り付け
行数表示
:set numberで行数表示/:set no numberで非表示

補完機能
ファイル名の先頭文字を入れてTabキーを押すと補完し、複数の場合は候補表示してくれる。

ていうかここ参照でいいような。
細かい解説
viコマンド リファレンス

その中間かな?解説
vi / vim コマンド一覧

大きな文字でやさしく解説
viエディタでの編集・操作コマンド

2011年3月7日月曜日

3/7覚書

1時間目
二次元配列の肝がキタ━━゚+.ヽ(≧▽≦)ノ.+゚━━ ッ ! ! !
kuku.php

require( "./libs/Smarty.class.php" );
$smarty = new Smarty();

for ($i = 1; $i < 10; $i++) {
 for ($j = 1; $j < 10; $j++) {
  //二次元配列の生成
  $num[$i][] = $i*$j;
  }
}

$smarty -> assign( "num", $num );
$smarty -> display("kuku.tpl");

kuku.tpl

<html>
<head>
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8" />
</head>
<body>

<table border=1>
<caption>九九の段・二次元配列</caption>
 <tr>
 {foreach from = $num item = n}
  {foreach from = $n item = c}
  <td height="25" width="25" align="center">
  {$c}
  </td>
  {/foreach}
 </tr>
 {/foreach}
</table>
</body>
</html>
$num[$i][]にすることで二次元配列となる。
[$i]
☆1~9までの数字が入る
[]
☆入れ子のforが回るたびに$i*$jの値が追加されていく
$num[$i][1(1*1)][2][3][4][5].....
[$i][2(2*1)][4][6][8][10].....
[$i][3(3*1)][6][9][12][15].....



2時間目
二次元配列を元にBBSのreplyも出すよー。

方法は二つ。
whileを入れ子にする。
→この方法はやぎーに聞いてくだしあ;
whileを入れ子にしない。
おいらはこっち。
【必須】commentのidとreplyのidを紐付ける。

index.php
require( "./libs/MySmarty.class.php" );

//mysql に接続する
require_once './db_connect.php';

// クエリを送信する
$sql = "SELECT * FROM comment where delete_flg = 0 order by created_at desc";
$result = mysql_query($sql);
while ($row = mysql_fetch_array($result)) {
 $data[] = $row;
}

//クエリを送信する(返信テーブル)
$sql = "SELECT * FROM reply where delete_flg=0 order by created_at desc";
$result1 = mysql_query($sql);

while ($row2 = mysql_fetch_array($result1)) {
 $repdata[] = $row2;
}

$smarty = new MySmarty();
$smarty -> assign( "index_list", $data );
$smarty -> assign( "reply_list", $repdata );
$smarty -> display( "index.tpl" );

//print_r($data);
//print_r($repdata);

index.tpl
<!-- 投稿内容 -->
{{foreach from = $index_list item =num}}
 <div style="border:1px solid #ddd;margin-bottom:10px;padding:5px;">
 {{if $num.url neq NULL}}
 <a href="{{$num.url}}">{{$num.nickname}}</a> さんの投稿
 {{else}}{{$num.nickname}}さんの投稿
 {{/if}}
  
 {{if $num.mail1 neq NULL}}
 <a href="mailto:{{$num.mail1}}">メール</a>
 {{/if}}
   <a href="./delete.php?comment_id={{$num.id}}">削除</a>
 <br>
 {{$num.content}}
 <br>
 {{if $num.photo neq NULL}}
 <IMG SRC="./img/{{$num.photo}}" width=200>
 {{/if}}
 <br>
 <br>
 {{if $num.photo2 neq NULL}}
 <IMG SRC="./img2/{{$num.photo2}}" width=200>
 {{/if}}
 <br>
 {{$num.created_at}}
 <br>
 <a href="reply.php?comment_id={{$num.id}}">返信する</a>
 </div>

 <!-- 返信内容 -->
  {{foreach from = $reply_list item =num2}}
   {{if $num2.comment_id eq $num.id}}
   {{*commentのidとreplyのidを紐付ける。*}}
 <div style="border:1px solid #ddd;margin-bottom:10px;padding:5px;
  background-color:#f3f3f3;margin-left:40px;">
 {{if $num2.url neq NULL}}
 <a href="{{$num2.url}}">{{$num2.nickname}}</a> さんの投稿
 {{else}}{{$num2.nickname}}さんの投稿
 {{/if}}
  
 {{if $num2.reply_mail neq NULL}}
 <a href="mailto:{{$num2.reply_mail}}">メール</a>
 {{/if}}
   <a href="./reply_delete.php?comment_id={{$num2.id}}">削除</a>
 <br>
 {{$num2.content}}
 <br>
 {{if $num2.reply_photo neq NULL}}
 <IMG SRC="./reply_photo/{{$num2.reply_photo}}" width=200>
 {{/if}}
 <br>
 <br>
 {{if $num2.reply_photo2 neq NULL}}
 <IMG SRC="./reply_photo2/{{$num2.reply_photo2}}" width=200>
 {{/if}}

 <br>
 {{$num2.created_at}}
 </div>
   {{/if}}
  {{/foreach}}
{{/foreach}}

3時間目
残りも片付けるよー。

4時間目
if文を使わない方式。こっちのほうがデータ処理が早い。

4次元配列
//SELECT文を発行し、commentテーブルからレコードを取得
$sql = "SELECT * FROM comment WHERE delete_flag = 0 ORDER BY created_at DESC";
$result = mysql_query($sql);

while ($comment = mysql_fetch_array($result)) {
 $row = array();
 //配列変数$rowの要素[comment]に配列$commnetが入るので、この時点で$rowは二次元配列
 $row['comment'] = $comment;
    //SELECT文を発行し、replyテーブルからレコードを取得
    $sql = "SELECT * FROM reply WHERE delete_flag = 0 AND comment_id = 
'".$comment["id"]."'ORDER BY created_at DESC";
    $result1 = mysql_query($sql);

    if($result1) {
        while ($reply = mysql_fetch_array($result1)) {
         //配列変数$rowの要素[reply]の下にもう一つ配列を作り、
         そこに配列$replyが入るので、この時点で$rowは3次元配列
            $row['reply'][] = $reply;
        }
    }
 //配列変数$rowsに3次元配列$rowを格納するので、$rowsは4次元配列
    $rows[] = $row;
}

# 多重配列の表示確認
/*
print"<pre>";
print_r($rows);
print"</pre>";
*/

$smarty = new Smarty;
$smarty->assign('rows', $rows);
$smarty->display('index.tpl');

index3.は3次元だそうな。
デザイナーの負担にならないように構築することで、Smarty本来の機能を発揮できる。

階層イメージ
$rows━━
    ┗$row
      ┣comment
      ┣reply━
          ┣0
          ┣1
$smarty.session.~でsession使えるよ。

マジでくわっちょおわり~。

" ゚☆,。・:*:・゚★o(´▽`*)/♪Thanks♪\(*´▽`)o゚★,。・:*:・☆゚ "
" ゚☆,。・:*:・゚★o(´▽`*)/♪Thanks♪\(*´▽`)o゚★,。・:*:・☆゚ "
" ゚☆,。・:*:・゚★o(´▽`*)/♪Thanks♪\(*´▽`)o゚★,。・:*:・☆゚ "

2011年3月4日金曜日

3/4覚書

1時間目
FizzBuzz~
display忘れてたさ・・・・・・_| ̄|○
fizzbuzz.php
for ($i = 1; $i < 101; $i++) {
 $num_list[$i] = $i;
}
require( "./libs/Smarty.class.php" );
$smarty = new Smarty();
$smarty -> assign( "num_list", $num_list );
$smarty -> display("fizzbuzz.tpl");

fizzbuzz.tpl

<head>
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8" />
</head>
<body>

<table border=1>
<caption>FizzBuzz。3の倍数はFizz。5の倍数はBuzz。公倍数はFizzBuzz</caption>
 <tr>
 {foreach from = $num_list item = num}
 <td>
 {if $num is div by 3}Fizz{/if}
 {if $num is div by 5}Buzz{/if}
 {if (($num is not div by 3) && ($num is not div by 5))}{$num}
</td>
{/if}
</tr>
{/foreach}
</table>
</body>
</html>

2時間目
FizzBuzz続き~
出るには出たんだけど、trタグの位置がわからんかった。゜(゚´Д`゚)゜。
九九で多少は理解できるのかなあ・・・・・・。
プログラムは上から順に処理するが、Smartyでは上から順に処理される。
elseifを使うときはphpとは逆に記述しよう。

分離の意義。
HTML(tpl)とPHPの作業でどのようになってくるか。を理解するため。

3時間目
メモリ増設。私のはLatitude:D520。celeron Mゆえに最大2GBまでしか効かない。
しかもキーボードカバー外してからDIMM Aスロットがありやんの・・・
いいんちょに外し方てもらいつつやりかたを教わり、しのさんのやってみた。できた。
外し方はメーカーサイト参照。

4時間目~ラスト

BBSをBBS_Smartyにコピーして分離作業+メモリ増設続き。

投稿分だけはでましたが・・・・・・返信難しいよおおお><

理解がないのが悔しい。
明日釣りだけど考えます。ちっくしょー。

2011年3月3日木曜日

3/3覚書

ちょいと遅刻して午後から。自分のドジっぷりがなんだかなあ;

1時間目?
現場レベルでのSmartyのデリミタの扱いについて。
{}はJavaScriptでも使うので、Smartyと混在するとエラーの原因になるので、
回避のためにデリミタを変更したclassを継承させる。

/**********************************************************************

Smartyクラスを継承したMySmartyクラスを作成

コンストラクタの呼び出しが「Smarty()」ではなくて「__construct()」に
変わっているので注意

**********************************************************************/

include_once ( "Smarty.class.php" );

class MySmarty extends Smarty {
 function MySmarty() {
  $this -> left_delimiter = "{{";
  $this -> right_delimiter = "}}";
  $this -> __construct();
 }
}

2時間目?

Ex.SmartyでFizzBuzz。ifとforeachでつくろ~(宿題らしい)。
ファイル名はまんまfizzbuzz.phpとfizzbuzz.tpl。

3時間目

暗号化
md5()で暗号化処理の関数です。覚えておくとラッキー。

mysql_fetch_array = 通常配列+連想配列
楽だがデータ取得が2倍になるので多用は難しい。
mysql_fetch_assoc = 連想配列

mysql_fetch_row = 通常配列


ブラウザで出すとこうなる。エクセルの表をイメージするとわかりやすいかな。
Array//$dataの配列
(
[0] => Array//$rowの1行目の配列
(
[1] => Array//$rowの2行目の配列
(

4時間目
連想配列を表で出してみよう。
foreachelse ・・・・・・データが入っていない場合の判定を入れることでエラー表示回避。

<body>
<table border="1">
 <tr><th>No.</th><th>会員ID</th><th>パスワード</th><th>有効/無効</th></tr>
 {{foreach from = $member_list item = num}}
 <tr>
  <td>{{$num.member_id}}</td>
  <td>{{$num.member_name}}</td>
  <td>{{$num.password}}</td>
  <td>{{if $num.delete_flg == 0}}有効{{/if}}
  {{if $num.delete_flg == 1}}無効{{/if}}</td>//elseifもおk
 </tr>
 {{foreachelse}}
 <tr><td colspan="4">データがありません</td></tr>
 {{/foreach}}
</table>

5時間目
4時間目の内容で、POSTされたデータを扱う。
何がきても大丈夫なように|escape()を使うことでXSS対策になる。
「escape」は「htmlspcialchars」のこと~。
あとindex.tplから。
$blog.blog_date|date_format:'%Y年 %m月 %d日 %T'
でデータの日付表示を変更できるよ。
関数を使うときは|でつなげるよ。

【問題】0302問題
以下のログインフォームをMとVに分離してください
・login.php
・login.tpl

テンプレートファイルに
・ログインネーム($login_name)と
・ログインメッセージ($login_message)
を表示させてください

多分pho側にSmarty設定を入れるのは平気だと思う。
{{$login_name}}と{{$login_message}}だけ~(設定次第なので{}のひとつでもおk)

2011年3月2日水曜日

3/2覚書

1時間目
今後の進捗についての説明。

バーチャルホストのリカバー(;´д`)トホホ…
今までのlocalhostからsmarty_sampleって場所に変更したよ。
そもそもバーチャルホストって何?
ひとつのIPアドレスに擬似的に複数のドメインをかぶせることができる。
複数のweb(localhostとかsmarty_sample)をPC内でいくつも使えるようにするのだー。

だが、ここで落とし穴。
Windows内でバーチャルホストを複数設置すると挙動が怪しくなる。
VM入れてLinuxで設定しよう。
ってなことで。
封 印(#でコメントアウト)

あとこぼれ話。
設定ファイルを書き換えるときは必ずバックアップを取ろう。
書き換える前のファイルを名前をつけて保存でBAK_とかつけて別名保存するだけ!

コレだけでトラブルのときにすぐ復旧できるよ!

2時間目
とりあえずプログラムってなに? PHPってなに?
資料みれ。すっごいわかりやすいから。
・JavaScriptでバリデート(エラーチェック。)
 ブラウザだけで処理するからサーバー負荷がない。
 でもJavaScriptはオフにできる。
 →実務ではJavaScript+PHP両方のバリデートを行う。

・Noticeエラーもっかい
 Smarty_sampleにnotice_test.php作成。
 以下入力。
$num = $num1 + $num2;
print $num;
$text = $_POST["text"];
print $text;
 
 んでphp.iniの
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATEDを
error_reporting = E_ALL
; & ~E_NOTICE & ~E_DEPRECATED
 に変更。;にするとコメントアウトする。
 Apache再起動。

すると、Notice: Undefined variable:~で 
num1、num2、textそれぞれに対してNoticeエラーが出る。
コレはプログラムゆえに、変数の指定がないぜ~って言ってる。
ここでは。
おとといも書いたけど、これが残っていると、どこに設定ファイルがあるのかモロバレ。
ハッキング等を受ける可能性があるのだ。
なのでちゃんと決めてあげないといけない。

んじゃどうするのか? 自分もわからんのでしっかり勉強。

$num1 = 0 ;//変数の指定
$num2 = 0 ;//変数の指定

$num = $num1 + $num2;
print $num;

$_POST["text"] = NULL;//変数の指定

$text = $_POST["text"];
print $text;

POST、GET、SESSION、連想配列でNoticeエラーが出ているときは、
変数の前に@をつけておくと回避ができる。
@$numとか。$text = @$_POST["text"]とか。
現場レベルで一般的だが、会社の方針に従おう。

ちなみにeclipceでは変数の指定がちゃんとできているとファイルの下にツリーが出る。
赤枠のところ。出ていない場合はNoticeエラーの疑い強し。


・公開領域再び
 ブラウザに設定ファイルは置きません。
 階層上げておかないと攻撃されちゃうよ;y=ー( ゚д゚)・∵. ターン

3時間目
テンプレートエンジンてなに?
めっちゃ簡潔に言うとclass(変数と定数と関数)ファイルの集合体。
smartyは変数をアサインするときは$不要。
$smarty->assign(‘title’, ‘Smarty-test’); //「Smarty-test」という文字列を、テンプレート
側で「$title」と書けば使用できるようにする
表示させるときは{$title}
Smartyがやってることを簡単に言うと・・・
PHPファイル(****.php = Model)で
assignした変数を
displayで指定したテンプレートファイル(****.tpl = View)で
使用できるようにする
(=assign変数をテンプレートファイルに渡す)
+α(ifやforeachの使用も可)

講座の中ではテンプレート群の記述は不要。デフォルトで設定済み。
(だからWEB講座にも記述がない)
テンプレート群は実務ではプロジェクトと同じ階層に置くため、記述が必要になる。

■eclipseのPHP内のHTML構文エラー非表示設定
設定 → 一般 → エディタ → 構造化テキストエディタ → 検証(青字リンク) →
HTML構文バリデータ、HTML構文バリデータ(PHPファイル用)のチェックを2つとも外す。

4時間目
ダウンロードしたsmarty_lessonをeclipceにインポート。
練習問題
1.配列
$gender = array ( "m" => "男", "f" => "女" ) ;
これをSmartyで表示するときは、
{$gender.m}と書く。
2.if文
genderの値が「f」だったら「女」と表示するロジックを追加してください
それ以外は「未選択」と表示するロジックを追加してください
$gender = "f" ;
■性別:
{if $gender == "m"}
男
{elseif $gender == "f"}
女
{else}
未選択
{/if}

3.foreach文 生phpでもいいような希ガス。んでも覚えておくのだ。
$pref[1] = "北海道" ;
$pref[2] = "青森県" ;
$pref[3] = "岩手県" ;

■住所:
<select name = "pref">
 <option value = "" selected>選択してください</option>
 {foreach from = $pref item = pref_name key = num}
 <option value = "{$num}">{$pref_name}</option>
 {/foreach}
</select>

{}(デリミタ、ブレス)の直後と直前に余計な半角スペースがあると正常に動作しない。

4.foreach+if文
【問題】
年、月、日をプルダウンで選択できるように表示してください
→foreachを使用する
→まず年を作成する
→うまくいったら同じ要領で月と日も作る

【発展問題】
→現在の日付とループの日付が一致したらデフォルト選択という条件式をつける
if文中にはPHPの関数を使うことができる
・今回は関数「date()」を使用する
→現在の年を求めるには…date("Y")
→現在の月を求めるには…date("m")
→現在の日を求めるには…date("d")

5時間目
date.php
//年の配列を生成
for ( $i = 2000; $i <= date("Y")+3; $i ++ ){//2000年~2014年まで
 $year_list[$i] = $i;
}
//月の配列を生成
for($j = 1; $j <= 12; $j ++){//12月
 $month_list[$j] = $j;
}
//日の配列を生成
for($k = 1; $k <= 31; $k ++){//31日まで
 $day_list[$k] = $k;
}

date.tpl

<form action="">
<select name = "year">
 {foreach from = $year_list item = year}
 <option value = "{$year}"{if date("Y") == $year} selected{/if}>{$year}</option>
 {/foreach}

</select>年
<select name = "month">
 <option value = "" selected>選択してください</option>
 {foreach from = $month_list item = month}
 <option value = "{$month}"{if date("m") == $month} selected{/if}>{$month}</option>
 {/foreach}
</select>月
<select name = "day">
 <option value = "" selected>選択してください</option>
 {foreach from = $day_list item = day}
 <option value = "{$day}"{if date("d") == $day} selected{/if}>{$day}</option>
 {/foreach}
</select>日
</form>

閉じ}のないphp文の記述を理解していなかった・・・・・・。
いいんちょの言葉が頭の中でリプレイする。

2011年3月1日火曜日

3/1覚書

1時間目は
クラスの概念再び。
クラス図。これは概念だからね。
親から子へ継承できるよ。

☆オブジェクト指向
オブジェクト指向の考え方で割りといい感じの説明
ここだけ読んでもおk。

飛び飛び過ぎてつらい・・・・・・。

2時間目
smarty入門っぽいサイト
早わかりsmarty
いずれは見ようウノウラボ

PHP-users メーリングリスト
不明点もちゃんと書けば教えてくれるよ。質問内容は質問者の文章を参考にどぞ。

いつかは行こうPHP勉強会

さてSmarty設置とバーチャルホスト設定。
eclipce、XAMPP起動して・・・・・・sample_templateって名前でプロジェクト作成。

ダウンロードしたLatest Stable Releaseの
Smarty 3.0.7 (.tar.gz) (.zip) February 11th, 2011のzipを保存して解凍。
そこからlibsフォルダをC:\pleiades\xampp\htdocs\smarty_sample(実際のフォルダね)へコピー。

C:\pleiades\xampp\apache\conf\extra\httpd-vhosts.confをエディタで開く。
そんで一番下の所をコピーしてその下に貼り付けて、以下に改変。
一緒に##NameVirtualHost *:80ってあるから、##取るよ!

## Smartyサンプル##
<VirtualHost *:80>
    DocumentRoot "c:/pleiades/xampp/htdocs/smarty_sample"
    ServerName smarty_sample
    Directoryindex index.php index.html
    
    <Directory "c:/pleiades/xampp/htdocs/smarty_sample">
        AllowOverride All
        Allow from All
    </Directory>
</VirtualHost>
保存したらXAMPPでApache再起動。


3時間目
C:\WINDOWS\system32\drivers\etc\hostsをエディタで開き、最下部に下記追加。
## Smarty サンプル
127.0.0.1 smarty_sample
http://smarty_sample/で開くかチェック。
現時点ではIndex of /ってページが出れば成功。
意味を知ろう
127.0.0.1 【ループバックアドレス】
127.0.0.1 自分のlocalhostのこと。
hostsファイル 【hosts file】
localhostのIPアドレスやホスト名が記述されたシステムファイル。
名前解決 【name resolution】
DNSのこと。

今までのBBSとか住所録もバーチャルホストに組み込んでみよう。
ていうかこれやらないと今までの課題が見れなくなる;
<VirtualHost *:80>
    DocumentRoot "c:/pleiades/xampp/htdocs/address_book"
    ServerName address_book

4時間目

テンプレートからHTMLを呼び出すよ。
まずは以下のフォルダを作るよー。
templatesフォルダの名称は好きにつけていいけど、慣例でコレが多い。
たまにtplって省略できる。
これらのフォルダは攻撃対象になりうるため、本当は公開領域に置かない。
置くならhtdocs以上のフォルダに置く。
* templates
* templates_c
* config
* cache

んでtemlpatesフォルダにhello.tplファイルを作成。
smaty_sample直下にhello.phpを作成。
内容は以下。
//sumarty.classを読み込み
require('./libs/Smarty.class.php');

//smartyクラスのインスタンスを作成
$smarty = new Smarty;

//テンプレートファイルの置き場所を指定
$smarty ->template_dir="./templetes";

//変換したテンプレートファイルが置かれる場所
//コンパイル・ディレクトリ
//実際に実行されるphpファイル
$smarty ->compile_dir="./templetes_c";

//assignで変数名と値をセット
$smarty ->assign("name","world");
//displayでブラウザに出力
$smarty ->display("hello.tpl");


そしたらhttp://smarty_sample/hello.phpを開くと、
Hello,world! って文字だけ出るよ。

サーバーサイドスクリプト/クライアントサイドスクリプト
呼んで字のごとく。

コンパイルって何?
ヒトが書いたプログラムを機械がわかる言葉01 00 10・・・・・・などに翻訳してあげること。

5時間目
tpl内に{* *}でコメントがかける。ソースにも出ない。

配列でやてみよう。
array.php
//sumarty.classを読み込み
require('./libs/Smarty.class.php');

//smartyクラスのインスタンスを作成
$smarty = new Smarty;

//テンプレートファイルの置き場所を指定
$smarty ->template_dir="./templetes";

//変換したテンプレートファイルが置かれる場所
//コンパイル・ディレクトリ
//実際に実行されるphpファイル
$smarty ->compile_dir="./templetes_c";

$smarty ->assign("arch",
    array(
    "PHP",
    "ASP.NET",
     array("JSP","サーブレット")
     )
   );
$smarty -> display("array.tpl");

array.tpl
サーバーサイド技術には{$arch[0]}、{$arch[1]}、のような技術があります。
連想配列の入れ子の表示方法がわからんかった・・・・・・;