cakePHP 3 を 直接 触って 覚えてみることにした No.4
この記事は 2017年 2月 14日 に書かれた記事です。
わかってしまえば 大した事ないのですが 前回から ず〜と 悩んでました…
やっと ログイン画面を 作成することができたので 忘れないように メモしておきます
テーブル作成
管理者用 の ユーザ を 保存するための テーブル を 作成します
ユーザ名 メールアドレス パスワード を 1セット として Admins を作成します
bin/cake bake migration CreateAdmins username:string:unique email:string:unique password:string created modified -p Admin bin/cake migrations migrate -p Admin
コントローラー
コントローラー は Users として 作成します
plugins/Admin/src/Controller/UsersController.php
<?php
namespace Admin\Controller;
use Admin\Controller\AppController;
/**
* Users Controller
*
* @property \Admin\Model\Table\AdminTable $Admins
*/
class UsersController extends AppController
{
/**
* Index method
*
* @return \Cake\Network\Response|null
*/
public function index()
{
$this->set( 'title_for_layout', __( 'Admin List' ) );
$this->loadModel( 'Admin.Admins' );
$admins = $this->paginate( $this->Admins );
$this->set( compact( 'admins' ) );
$this->set( '_serialize', ['admins'] );
}
/**
* View method
*
* @param string|null $id Admin id.
* @return \Cake\Network\Response|null
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
*/
public function view( $id = null )
{
$this->set( 'title_for_layout', __( 'Admin Details' ) );
$this->loadModel( 'Admin.Admins' );
$admin = $this->Admins->get( $id, [
'contain' => []
] );
$this->set( 'admin', $admin );
$this->set( '_serialize', ['admin'] );
}
/**
* Add method
*
* @return \Cake\Network\Response|null Redirects on successful add, renders view otherwise.
*/
public function add()
{
$this->set( 'title_for_layout', __( 'Add Admin' ) );
$this->loadModel( 'Admin.Admins' );
$admin = $this->Admins->newEntity();
if( $this->request->is( 'post' ) ) {
$admin = $this->Admins->patchEntity( $admin, $this->request->data );
if( $this->Admins->save( $admin ) ) {
$this->Flash->success( __( 'The admin has been saved.' ) );
return $this->redirect( [ 'action' => 'index' ] );
}
$this->Flash->error( __( 'The admin could not be saved. Please, try again.' ) );
}
$this->set( compact( 'admin' ) );
$this->set( '_serialize', ['admin'] );
}
/**
* Edit method
*
* @param string|null $id Admin id.
* @return \Cake\Network\Response|null Redirects on successful edit, renders view otherwise.
* @throws \Cake\Network\Exception\NotFoundException When record not found.
*/
public function edit( $id = null )
{
$this->set( 'title_for_layout', __( 'Edit Admin' ) );
$this->loadModel( 'Admin.Admins' );
$admin = $this->Admins->get( $id, [
'contain' => []
] );
if( $this->request->is( [ 'patch', 'post', 'put' ] ) ) {
$admin = $this->Admins->patchEntity( $admin, $this->request->data );
if( $this->Admins->save( $admin ) ) {
$this->Flash->success( __( 'The admin has been saved.' ) );
return $this->redirect( [ 'action' => 'index' ] );
}
$this->Flash->error( __( 'The admin could not be saved. Please, try again.' ) );
}
$this->set( compact( 'admin' ) );
$this->set( '_serialize', ['admin'] );
}
/**
* Delete method
*
* @param string|null $id Admin id.
* @return \Cake\Network\Response|null Redirects to index.
* @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found.
*/
public function delete( $id = null )
{
$this->set( 'title_for_layout', __( 'Delete Admin' ) );
$this->loadModel( 'Admin.Admins' );
$this->request->allowMethod( [ 'post', 'delete' ] );
$admin = $this->Admins->get( $id );
if( $this->Admins->delete( $admin ) ) {
$this->Flash->success( __( 'The admin has been deleted.' ) );
} else {
$this->Flash->error( __( 'The admin could not be deleted. Please, try again.' ) );
}
return $this->redirect( [ 'action' => 'index' ] );
}
/**
* Login method
*/
public function login()
{
$this->set( 'title_for_layout', __( 'Login' ) );
$this->viewBuilder()->layout( 'admin.login' );
if( $this->request->is( 'post' ) ) {
$admin = $this->Auth->identify();
if( $admin ) {
$this->Auth->setUser( $admin );
return $this->redirect( $this->Auth->redirectUrl() );
}
$this->Flash->error( __( 'Invalid username or password, try again.' ) );
}
}
/**
* Logout method
*/
public function logout()
{
return $this->redirect( $this->Auth->logout() );
}
}
モデル
モデル は bake で 作ってしまいましょう
DB を 元に 作ってくれるので 非常に便利です!!
bin/cake bake model Admins -p Admin
単純に 作成しただけでは password は ハッシュ化されないので Entity という 機能を使って DB に 入れる直前に ハッシュ化 されるようにします
省略した形で書きます
plugins/Admin/src/Model/Entity/Admin.php
~ bake された 記述 ~
use Cake\Auth\DefaultPasswordHasher;
class Admin extends Entity
{
~ bake された 記述 ~
protected function _setPassword( $password )
{
return ( new DefaultPasswordHasher )->hash( $password );
}
}
ビュー
ビュー部分は Bootstrap の コーディングが必要ですので ソースを ガシガシ 載せます!!
plugins/Admin/src/Template/Layout/admin.login.ctp
<!DOCTYPE html> <html lang="ja"> <head> <meta name='robots' content='noindex,follow'> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="format-detection" content="telephone=no,address=no,email=no"> <?= $this->Html->css( 'Admin.bootstrap.min' ).PHP_EOL ?> <?= $this->Html->css( 'Admin.bootstrap.diff' ).PHP_EOL ?> <?= $this->Html->css( 'Admin.admin.login' ).PHP_EOL ?> <title><?= $title_for_layout ?></title> <?= $this->Html->meta( 'icon', 'Admin./favicon/admin-favicon.ico' ).PHP_EOL ?> <?= $this->Html->meta( [ 'rel' => 'apple-touch-icon-precomposed', 'sizes' => '16x16', 'link' => 'Admin./favicon/admin-favicon.ico', ] ).PHP_EOL ?> </head> <body> <?= $this->fetch( 'content' ) ?> </body> <?= $this->Html->script( 'Admin.jquery.min' ).PHP_EOL ?> <?= $this->Html->script( 'Admin.tether.min' ).PHP_EOL ?> <?= $this->Html->script( 'Admin.bootstrap.min' ).PHP_EOL ?> </html>
plugins/Admin/src/Template/Users/index.ctp
<section class="container">
<header class="form-signin-heading">
<h1><?= $title_for_layout ?></h1>
</header>
<?= $this->Flash->render() ?>
<table class="table table-hover table-responsive">
<thead>
<tr>
<th><?= $this->Paginator->sort( 'id' ) ?></th>
<th><?= $this->Paginator->sort( 'username' ) ?></th>
<th colspan="3"><?= __( 'Actions' ) ?></th>
</tr>
</thead>
<tbody>
<?php foreach( $admins as $admin ) : ?>
<tr>
<td><?= $this->Number->format( $admin->id ) ?></td>
<td><?= h( $admin->username ) ?></td>
<td><?= $this->Html->link( __( 'View' ), [ 'action' => 'view', $admin->id ], [ 'class' => 'btn btn-secondary' ] ) ?></td>
<td><?= $this->Html->link( __( 'Edit' ), [ 'action' => 'edit', $admin->id ], [ 'class' => 'btn btn-secondary' ] ) ?></td>
<td><?= $this->Form->postLink( __( 'Delete' ), [ 'action' => 'delete', $admin->id ], [ 'class' => 'btn btn-secondary' ], [ 'confirm' => __( 'Are you sure you want to delete # {0}?', $admin->id ) ] ) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<nav aria-label="Page navigation example">
<ul class="pagination">
<?= $this->Paginator->first( '<< ' . __( 'first' ) ).PHP_EOL ?>
<?= $this->Paginator->prev( '< ' . __( 'previous' ) ).PHP_EOL ?>
<?= $this->Paginator->numbers().PHP_EOL ?>
<?= $this->Paginator->next( __( 'next' ) . ' >' ).PHP_EOL ?>
<?= $this->Paginator->last( __( 'last' ) . ' >>' ).PHP_EOL ?>
</ul>
<p><?= $this->Paginator->counter( [ 'format' => __( 'Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total' ) ] ) ?></p>
</nav>
</section>
plugins/Admin/src/Template/Users/view.ctp
<section class="container">
<header class="form-signin-heading">
<h1><?= $title_for_layout ?></h1>
</header>
<?= $this->Flash->render() ?>
<table class="table table-hover table-responsive">
<tbody>
<tr>
<th><?= __( 'ID' ) ?></td>
<td><?= $this->Number->format( $admin->id ) ?></td>
</tr>
<tr>
<th><?= __( 'Username' ) ?></th>
<td><?= h( $admin->username ) ?></td>
</tr>
<tr>
<th><?= __( 'E-mail' ) ?></th>
<td><?= h( $admin->email ) ?></td>
</tr>
<tr>
<th><?= __( 'Password' ) ?></th>
<td> = Secret = </td>
</tr>
</tbody>
</table>
</section>
plugins/Admin/src/Template/Users/add.ctp
<section class="container">
<div class="form-signin">
<header class="form-signin-heading">
<h1><?= $title_for_layout ?></h1>
<h2><?= __( 'Please enter user name and password.' ) ?></h2>
</header>
<?= $this->Flash->render() ?>
<div class="users form">
<?= $this->Form->create( $admin ).PHP_EOL ?>
<?= $this->Form->input( 'username', [ 'class' => 'form-control', 'placeholder' => 'username' ] ).PHP_EOL; ?>
<?= $this->Form->input( 'email', [ 'class' => 'form-control', 'placeholder' => 'email' ] ).PHP_EOL; ?>
<?= $this->Form->input( 'password', [ 'class' => 'form-control', 'placeholder' => 'password' ] ).PHP_EOL; ?>
<?= $this->Form->button( __( 'Add' ), [ 'class' => 'btn btn-lg btn-primary btn-block' ] ).PHP_EOL; ?>
<?= $this->Form->end().PHP_EOL; ?>
</div>
</div>
</section>
plugins/Admin/src/Template/Users/edit.ctp
<section class="container">
<div class="form-signin">
<header class="form-signin-heading">
<h1><?= $title_for_layout ?></h1>
<h2><?= __( 'Please enter user name and password.' ) ?></h2>
</header>
<?= $this->Flash->render() ?>
<div class="users form">
<?= $this->Form->create( $admin ).PHP_EOL ?>
<?= $this->Form->input( 'username', [ 'class' => 'form-control', 'placeholder' => 'username' ] ).PHP_EOL; ?>
<?= $this->Form->input( 'email', [ 'class' => 'form-control', 'placeholder' => 'email' ] ).PHP_EOL; ?>
<?= $this->Form->input( 'password', [ 'class' => 'form-control', 'placeholder' => 'password' ] ).PHP_EOL; ?>
<?= $this->Form->button( __( 'Submit' ), [ 'class' => 'btn btn-lg btn-primary btn-block' ] ).PHP_EOL; ?>
<?= $this->Form->end().PHP_EOL; ?>
</div>
</div>
</section>
plugins/Admin/src/Template/Users/login.ctp
<section class="container">
<div class="form-signin">
<header class="form-signin-heading">
<h1><?= $title_for_layout ?></h1>
<h2><?= __( 'Please enter user name and password.' ) ?></h2>
</header>
<?= $this->Flash->render() ?>
<div class="users form">
<?= $this->Form->create().PHP_EOL ?>
<?= $this->Form->input( 'username', [ 'class' => 'form-control', 'placeholder' => 'username' ] ).PHP_EOL ?>
<?= $this->Form->input( 'password', [ 'class' => 'form-control', 'placeholder' => 'password' ] ).PHP_EOL ?>
<?= $this->Form->button( __( 'Login' ), [ 'class' => 'btn btn-lg btn-primary btn-block' ] ).PHP_EOL ?>
<?= $this->Form->end().PHP_EOL ?>
</div>
</div>
</section>
ユーザ登録
http://localhost:8888/my_app_name/admin/users/add から 最初のユーザを 登録します
これで ハッシュ化された パスワードが 生成されます
ログイン認証
/plugins/Admin/src/Controller/AppController.php
class AppController extends BaseController
{
public function initialize()
{
parent::initialize();
$this->loadComponent( 'Auth', [
'loginRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'front-page',
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login',
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login',
],
'authenticate' => [
'Form' => [
'userModel' => 'Admin.Admins',
]
],
'sessionKey' => 'Auth.Admin',
] );
}
~ bake された 記述 ~
}
これで ログイン ログアウト が できるようになりました
UsersController で $this->loadModel( ‘Admin.Admins’ ); の Admin. が わからなくて パスワードが ハッシュ化されなくて ずっと悩んでました…
I referred to プラグイン - CakePHP Cookbook 3.X ドキュメント.
https://book.cakephp.org/3.0/ja/plugins.html
手探りで 勉強しているので 間違っていたら ご指摘いただけると助かります!!