cakephpでtodoアプリを作る

cakephp todoapp tutorial

 

参考

 

CakePHPでBakeしてみる

 

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']);
    }

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください