てくてくあるく

WordPress の テーマ とか プラグイン に ついて 勉強しています

わかってしまえば 大した事ないのですが 前回から ず〜と 悩んでました…

やっと ログイン画面を 作成することができたので 忘れないように メモしておきます


テーブル作成


管理者用 の ユーザ を 保存するための テーブル を 作成します
ユーザ名 メールアドレス パスワード を 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. が わからなくて パスワードが ハッシュ化されなくて ずっと悩んでました…


プラグイン - CakePHP Cookbook 3.X ドキュメントを参考にさせていただきました。
https://book.cakephp.org/3.0/ja/plugins.html

手探りで 勉強しているので 間違っていたら ご指摘いただけると助かります!!

Related Article

cakePHP 3 を 直接 触って 覚えてみることにした No.5

詳細へ »

ポストメタ が 肥大化して 管理ページが 遅くなっていた…

詳細へ »