チャット作るよ。10日目
コメント書き込みとログイン周りを実装する。
昔ながらのバージョンはこれでひとまず完了。
コメント書き込みのアクションを作る。
ログイン済みユーザのコメントPOSTを受けとってファイルに書き込む。
まずテストケース。
<?php class CommentActionTest extends PHPUnit_Framework_TestCase { /** * アプリケーションディレクトリ */ const APP_DIR_PATH = '/var/project/chat/fw/site'; public function setUp() { // インスタンスを生成 $this->act = new CommentAction(); $this->member = new Member(FILE_MEMBER, 300); $this->arc = new Archive(FILE_ARCHIVE, 30); // アクションを初期化 $config = array( 'appDirPath' => self::APP_DIR_PATH, 'renderer' => new Renderer() ); $this->act->initialize($config); } public function testRun() { // 実行前、データが0件であること $this->assertEquals(0, count($this->arc->getAll())); // postパラメータをセット $_POST['comment'] = 'Test'; // アクション実行 $this->act->run(); // セッションがないのでデータに変化は起きないこと $this->assertEquals(0, count($this->arc->getAll())); $this->assertEquals(0, count($this->member->getAll())); } public function testRunWithIdentity() { // 実行前、データが0件であること $this->assertEquals(0, count($this->arc->getAll())); $this->assertEquals(0, count($this->member->getAll())); // 新規メンバーとしてデータ登録 $name = 'Test'; $id = $this->member->add($name); $identity = array( 'id' => $id, 'name' => $name ); // セッションにセット $_SESSION['identity'] = $identity; // 登録データを取得して、保持しておく $members = $this->member->getAll(); $user = $members[0]; // 更新時間をずらすため1秒待機 sleep(1); // postパラメータをセット $comment = 'TestTestTest'; $_POST['comment'] = $comment; // アクション実行 $this->act->run(); // ログにpostしたコメントが登録されること $logs = $this->arc->getAll(); $this->assertEquals(1, count($logs)); $this->assertEquals($name, $logs[0]['name']); $this->assertEquals($comment, $logs[0]['comment']); // ユーザのタイムスタンプが更新されること $members = $this->member->getAll(); $update = $members[0]; $this->assertEquals(1, count($members)); $this->assertEquals($user['id'], $update['id']); $this->assertEquals($user['name'], $update['name']); $this->assertLessThan($update['tstamp'], $user['tstamp']); } public static function tearDownAfterClass() { // データファイルの後始末 if(file_exists(FILE_ARCHIVE)) { unlink(FILE_ARCHIVE); } if(file_exists(FILE_MEMBER)) { unlink(FILE_MEMBER); } } }
アクションクラス。
<?php class CommentAction extends Action { public function run() { if(isset($_SESSION['identity']) && isset($_POST['comment'])) { // ログイン済みで書き込みポストがある場合 $identity = $_SESSION['identity']; $comment = $_POST['comment']; // アーカイブにデータ追加 $arc = new Archive(FILE_ARCHIVE, 30); $arc->add($identity['name'], $comment); // 有効期限を更新して、GCも実行。 $member = new Member(FILE_MEMBER, 300); $member->update($identity['id']); $member->gc(); } header("HTTP/1.1 301 Moved Permanently"); header("Location: /?a=log"); } }
ファイル書き込みと同時に、ユーザの期限を延長と期限切れユーザデータの削除も行う。
処理後にリダイレクトさせて書き込みログの表示に飛ばす。
ログインアクションを作る。
ログインっていうかチャットに参加的な部分。
テストケース。
<?php class LoginActionTest extends PHPUnit_Framework_TestCase { /** * アプリケーションディレクトリ */ const APP_DIR_PATH = '/var/project/chat/fw/site'; public function setUp() { // インスタンスの生成と初期化 $this->act = new LoginAction(); $config = array( 'appDirPath' => self::APP_DIR_PATH, 'renderer' => new Renderer() ); $this->act->initialize($config); } public function testRun() { // postパラメータを作成 $name = 'Test'; $_POST['name'] = $name; // 実行前、データがからであること $member = new Member(FILE_MEMBER, 300); $this->assertEquals(0, count($member->getAll())); $arc = new Archive(FILE_ARCHIVE, 30); $this->assertEquals(0, count($arc->getAll())); // アクション実行 $this->act->run(); // 実行後、新規メンバーとして追加されること $members = $member->getAll(); $this->assertEquals(1, count($members)); $identity = $members[0]; $this->assertEquals($name, $identity['name']); // セッションへユーザデータが登録されていること $this->assertEquals($_SESSION['identity']['name'], $identity['name']); // ログにユーザ追加データが登録されていること $logs = $arc->getAll(); $this->assertEquals(1, count($logs)); $this->assertEquals($name, $logs[0]['name']); $this->assertEquals('Welcome!', $logs[0]['comment']); } public function testRunWithNoName() { // 実行前データがからであること $member = new Member(FILE_MEMBER, 300); $this->assertEquals(0, count($member->getAll())); $arc = new Archive(FILE_ARCHIVE, 30); $this->assertEquals(0, count($arc->getAll())); // アクション実行 $this->act->run(); // アクション実行後、Unknownユーザとしてユーザ追加されていること $members = $member->getAll(); $this->assertEquals(1, count($members)); $identity = $members[0]; $this->assertEquals('Unknown', $identity['name']); // セッションへユーザデータが登録されていること $this->assertEquals($_SESSION['identity']['name'], $identity['name']); } public function tearDown() { // テストデータの後始末 if(file_exists(FILE_ARCHIVE)) { unlink(FILE_ARCHIVE); } if(file_exists(FILE_MEMBER)) { unlink(FILE_MEMBER); } } }
アクションクラス。
<?php class LoginAction extends Action { public function run() { // ユーザ名初期化 $name = 'Unknown'; if(isset($_POST['name']) && mb_strlen($_POST['name']) > 0) { // nameがPOSTパラメータにあればユーザ名に使う $name = $_POST['name']; } // メンバーに追加 $member = new Member(FILE_MEMBER, 300); $id = $member->add($name); // 認証をセッションに保持 $_SESSION['identity'] = array( 'id' => $id, 'name' => $name ); // 書き込みログに入室を追加 $arc = new Archive(FILE_ARCHIVE, 30); $arc->add($name, 'Welcome!'); // トップへリダイレクト header("HTTP/1.1 301 Moved Permanently"); header("Location: /"); } }
ユーザ名がなければ名無しさん扱いにする。
参加をログに追加して、リダイレクトさせる。
ログアウトアクションを作る。
退場的な部分。
テストケース。
<?php class LogoutActionTest extends PHPUnit_Framework_TestCase { /** * アプリケーションディレクトリ */ const APP_DIR_PATH = '/var/project/chat/fw/site'; public function setUp() { // インスタンスの生成と初期化 $this->act = new LogoutAction(); $config = array( 'appDirPath' => self::APP_DIR_PATH, 'renderer' => new Renderer() ); $this->act->initialize($config); } public function testRun() { // テストユーザを登録 $name = 'Test'; $member = new Member(FILE_MEMBER, 300); $id = $member->add($name); $this->assertEquals(1, count($member->getAll())); // セッションにテストユーザデータをセット $_SESSION['identity'] = array( 'id' => $id, 'name' => $name ); // アクション実行 $this->act->run(); // ログに退室データが追加されていること $arc = new Archive(FILE_ARCHIVE, 30); $log = $arc->getAll(); $this->assertEquals(1, count($log)); $this->assertEquals('Good Bye!', $log[0]['comment']); $this->assertEquals($name, $log[0]['name']); // テストユーザデータが削除されていること $this->assertEquals(0, count($member->getAll())); // セッションからデータが削除されていること $this->assertFalse(isset($_SESSION['identity'])); } public static function tearDownAfterClass() { // テストデータの後始末 if(file_exists(FILE_ARCHIVE)) { unlink(FILE_ARCHIVE); } if(file_exists(FILE_MEMBER)) { unlink(FILE_MEMBER); } } }
アクションクラス。
<?php class LogoutAction extends Action { public function run() { if(isset($_SESSION['identity'])) { // ログイン済みの場合、解除処理 $identity = $_SESSION['identity']; // 書き込みログに退出を記録 $arc = new Archive(FILE_ARCHIVE, 30); $arc->add($identity['name'], 'Good Bye!'); // メンバーから削除 $member = new Member(FILE_MEMBER, 300); $member->remove($identity['id']); // 認証を解除 unset($_SESSION['identity']); } // トップへリダイレクト header("HTTP/1.1 301 Moved Permanently"); header("Location: /"); } }
退場を書き込みして、ユーザデータとセッション消してリダイレクト。
昔ながらの版はさくっと作ろうと思ったのに、
「10日で…」本の1日相当に随分かかってしまった…。無念。
作りが甘い部分いっぱいあるし。中途半端になっちゃった。
作りながら記録付けるのって大変だ。