cakephp todoapp tutorial
参考
install
sudo apt-get install taksel sudo tasksel install lamp-server sudo apt-get install composer sudo apt-get install php7.0-intl php7.0-mbstring php7.0-sqlite
create new app
composer create-project --prefer-dist cakephp/app todoapp
run develop server
bin/cake server
create sqlite3 db
create db
sqlite3 db.sqlite3
create user table
create table users( id integer primary key, username varchar(50), password varchar(50), role varchar(20), created datetime default null, modified datetime default null );
create task table
create table tasks( id integer primary key, user_id int, title text, content text, created datetime, due_date datetime );
.exit
edit condigure db
config/app.phpを編集
DS=DirectorySeparator
'Datasources' => [ 'default' => [ 'className' => 'Cake\Database\Connection', 'driver' => 'Cake\Database\Driver\Sqlite', 'persistent' => false, //'host' => 'localhost', //'port' => 'non_standard_port_number', 'username' => '', 'password' => '', 'database' => ROOT.DS.'db.sqlite3', 'encoding' => 'utf8', 'timezone' => 'UTC', 'flags' => [], 'cacheMetadata' => true, 'log' => false, //省略 ], ],
create model controller template
bin/cake bake all Users bin/cake bake all Tasks
パスワードのハッシュ化
use Cake\Auth\DefaultPasswordHasher;
class User extends Entity { // ... protected function _setPassword($password) { if (strlen($password) > 0) { return (new DefaultPasswordHasher)->hash($password); } } // ... }
ユーザー認証なしで実行できるアクションメソッドを指定
UsersControllerのuseの部分に追記
use Cake\Event\Event;
UsersControllerクラスに追加
public function beforeFilter(Event $event) { parent::beforeFilter($event); $this->Auth->allow(['index','add','login']); }
ログイン処理の実装
AppControllerのinitializeメソッドでloadComponentする
$this->loadComponent('Auth',[ 'authenticate' => [ 'Form' => [ // 認証の種類を指定。Form,Basic,Digestが使える。デフォルトはForm 'fields' => [ // ユーザー名とパスワードに使うカラムの指定。省略した場合はusernameとpasswordになる 'username' => 'username', // ユーザー名のカラムを指定 'password' => 'password' //パスワードに使うカラムを指定 ] ] ], 'loginRedirect' => [ // ログイン後に遷移するアクションを指定 'controller' => 'Users', 'action' => 'index' ], 'logoutRedirect' => [ // ログアウト後に遷移するアクションを指定 'controller' => 'Users', 'action' => 'index', ], 'loginAction' => [ // ログインが必要なときに遷移するアクション 'controller' => 'Users', 'action' => 'index', ], 'authError' => 'ログインできませんでした。ログインしてください。', // ログインに失敗したときのFlashメッセージを指定(省略可) ]);
UsersControllerクラスにメソッドを追加
これらのメソッドにpostすることでログインやログアウトができる
public function login(){ $user = $this->Auth->identify(); if($user){ $this->Auth->setUser($user); return $this->redirect($this->Auth->redirectUrl()); }else{ $this->Flash->error(__('認証エラー')); } } public function logout() { $this->request->session()->destroy(); // セッションの破棄 return $this->redirect($this->Auth->logout()); // ログアウト処理 }
ログインしてるかどうかはuserメソッドで判定する。以下をindexアクションメソッドに追加
$user = $this->Auth->user(); if($user){ $this->set('login_user',$user); }
ログインフォームはこんな感じでつくる
<h3>Login</h3> <?= $this->Form->create('Login',array('url'=>array('controller'=>'Users','action'=>'login'))) ?> <fieldset> <?php echo $this->Form->control('username'); echo $this->Form->control('password'); ?> </fieldset> <?= $this->Form->button(__('Submit')) ?> <?= $this->Form->end() ?>
ログアウトフォーム
<h3>logout</h3> <?= $this->Form->create('Login',array('url'=>array('controller'=>'Users','action'=>'logout'))) ?> <?= $this->Form->button(__('Submit')) ?> <?= $this->Form->end() ?>
ログインしているかどうかを表示
<?php if(isset($login_user)){ echo '<p>ログイン中のユーザーは'.$login_user['username'].'です</p>'; }else{ echo '<p>ログインしていません</p>'; } ?>
タスクリストの実装
TasksControllerのuse部分に以下を記述
use Cake\Event\Event;
class内にメソッドとして以下記述
public function beforeFilter(Event $event) { parent::beforeFilter($event); //$this->Auth->allow(['index','add']); }
addメソッドでは、現在ログイン中のユーザーのタスクとして登録できるようにする
public function add() { $task = $this->Tasks->newEntity(); if ($this->request->is('post')) { $task = $this->Tasks->patchEntity($task, $this->request->getData()); //追記:ユーザーIDをタスクに紐付ける $user = $this->Auth->user(); $task['user_id'] = $user['id']; //ここまで if ($this->Tasks->save($task)) { $this->Flash->success(__('The task has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('The task could not be saved. Please, try again.')); } $users = $this->Tasks->Users->find('list', ['limit' => 200]); $this->set(compact('task', 'users')); $this->set('_serialize', ['task']); }
indexメソッドではログイン中のユーザーIDのタスクのみ表示する
public function index() { $this->paginate = [ 'contain' => ['Users'] ]; $user = $this->Auth->user(); $tasks = $this->paginate($this->Tasks->find('all',[ 'conditions'=>[ 'Tasks.user_id'=>$user['id'] ] ])); $this->set(compact('tasks')); $this->set('_serialize', ['tasks']); }
view、edit、deleteメソッドではタスクを登録したユーザー以外のタスクの操作を禁止する
public function view($id = null) { $task = $this->Tasks->get($id, [ 'contain' => ['Users'] ]); //ここから $user = $this->Auth->user(); if($task['user_id'] != $user['id']){ $this->Flash->error(__('不正な操作です')); $this->redirect(['action'=>'index']); } //ここまで $this->set('task', $task); $this->set('_serialize', ['task']); } public function edit($id = null) { $task = $this->Tasks->get($id, [ 'contain' => [] ]); //ここから $user = $this->Auth->user(); if($task['user_id'] != $user['id']){ $this->Flash->error(__('不正な操作です')); $this->redirect(['action'=>'index']); } //ここまで if ($this->request->is(['patch', 'post', 'put'])) { $task = $this->Tasks->patchEntity($task, $this->request->getData()); if ($this->Tasks->save($task)) { $this->Flash->success(__('The task has been saved.')); return $this->redirect(['action' => 'index']); } $this->Flash->error(__('The task could not be saved. Please, try again.')); } $users = $this->Tasks->Users->find('list', ['limit' => 200]); $this->set(compact('task', 'users')); $this->set('_serialize', ['task']); } public function delete($id = null) { $this->request->allowMethod(['post', 'delete']); $task = $this->Tasks->get($id); //ここから $user = $this->Auth->user(); if($task['user_id'] != $user['id']){ $this->Flash->error(__('不正な操作です')); $this->redirect(['action'=>'index']); } //ここまで if ($this->Tasks->delete($task)) { $this->Flash->success(__('The task has been deleted.')); } else { $this->Flash->error(__('The task could not be deleted. Please, try again.')); } return $this->redirect(['action' => 'index']); }