概要
本記事では、CakePHPを使って、顧客管理システムを作ることを目的として、システムへの認証機能から順を追って説明していきます。
前提
CakePHPがインストールされていること。
下準備
アプリを新規作成する。
$ composer create-project --prefer-dist cakephp/app [アプリ名]
TIPSとして、上記コマンドはやや長いので、エイリアスを貼ることをおすすめします。
$ alias cakenewapp='composer create-project --prefer-dist cakephp/app'
$ cakenewapp [アプリ名]
MySQLに新規データベースを作成する。
mysql> create database [データベース名]
Query OK, 1 row affected (0.03 sec)
config設定を変更する。(config/app.php)
'Datasources' => [
'default' => [
'className' => 'Cake\Database\Connection',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
/**
* CakePHP will use the default DB port based on the driver selected
* MySQL on MAMP uses port 8889, MAMP users will want to uncomment
* the following line and set the port accordingly
*/
//'port' => 'nonstandard_port_number',
'username' => 'my_app', <=これ
'password' => 'secret', <=これ
'database' => 'my_app', <=これ
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'log' => false,
組み込みのWEBサーバを起動して、テストページにアクセスし、設定内容が問題無いか確認する。
$ bin/cake server -H 0.0.0.0
認証機能の実装
MVCを順に作成していくことで、認証機能が簡単に実装できます。(作成する順番としては、M->C->Vですが)
Model
userテーブルを作成する。
mysql> CREATE TABLE users (
-> id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
-> username VARCHAR(50),
-> password VARCHAR(255),
-> role VARCHAR(20),
-> created DATETIME DEFAULT NULL,
-> modified DATETIME DEFAULT NULL
-> );
Query OK, 0 rows affected (0.38 sec)
UsersTableクラスを定義するため、src/Model/Table/UsersTable.php
を作成する。
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class UsersTable extends Table
{
public function validationDefault(Validator $validator)
{
return $validator
->notEmpty('username', 'A username is required')
->notEmpty('password', 'A password is required')
->notEmpty('role', 'A role is required')
->add('role', 'inList', [
'rule' => ['inList', ['admin', 'user']],
'message' => 'Please enter a valid role'
]);
}
}
Userクラスのエンティティを定義するため、src/Model/Entity/User.php
を作成する。(Usersではなく、Userであることに注意!)
<?php
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;
class User extends Entity
{
protected $_accessible = [
'*' => true,
'id' => false
];
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
}
Controller
認証機能を有効にするため、AppControler(src/Controller/AppController.php
)を修正する。
public function initialize() /* modify */
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authorize' => ['Controller'],
'loginRedirect' => [
'controller' => 'Users',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login'
]
]);
}
public function isAuthorized($user) /* add */
{
return false;
}
UsersControllerを定義するため、src/Controller/UsersController.php
を作成する。
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
class UsersController extends AppController
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow(['add', 'logout']);
}
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
}
$this->Flash->error(__('Invalid username or password, try again'));
}
}
public function logout()
{
return $this->redirect($this->Auth->logout());
}
public function isAuthorized($user)
{
return true;
}
public function index()
{
$this->set('users', $this->Users->find('all'));
}
public function view($id)
{
$user = $this->Users->get($id);
$this->set(compact('user'));
}
public function add()
{
$user = $this->Users->newEntity();
if ($this->request->is('post')) {
$user = $this->Users->patchEntity($user, $this->request->data);
if ($this->Users->save($user)) {
$this->Flash->success(__('The user has been saved.'));
return $this->redirect(['action' => 'add']);
}
$this->Flash->error(__('Unable to add the user.'));
}
$this->set('user', $user);
}
}
View
ユーザ登録画面のテンプレートを定義するため、src/Template/Users/add.ctp
を作成する。
<div class="users form">
<?= $this->Form->create($user) ?>
<fieldset>
<legend><?= __('Add User') ?></legend>
<?= $this->Form->input('username') ?>
<?= $this->Form->input('password') ?>
<?= $this->Form->input('role', [
'options' => ['admin' => 'Admin', 'user' => 'user']
]) ?>
</fieldset>
<?= $this->Form->button(__('Submit')); ?>
<?= $this->Form->end() ?>
</div>
ログイン画面のテンプレートを定義するため、src/Template/Users/login.ctp
を作成する。
<div class="users form">
<?= $this->Flash->render('auth') ?>
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('Please enter your username and password') ?></legend>
<?= $this->Form->input('username') ?>
<?= $this->Form->input('password') ?>
</fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>
ユーザ一覧画面のテンプレートを定義するため、src/Template/Users/index.ctp
を作成する。
<h1>users</h1>
<table>
<tr>
<th>Id</th>
<th>Username</th>
</tr>
<?php foreach ($users as $user): ?>
<tr>
<td><?= $user->id ?></td>
<td><?= $this->Html->link($user->username, ['action' => 'view', $user->id]) ?></td>
</tr>
<?php endforeach; ?>
</table>
ユーザ詳細画面のテンプレートを定義するため、src/Template/Users/view.ctp
を作成する。
<h1><?= h($user->id) ?></h1>
<p><?= h($user->username) ?></p>
これで、簡単に認証の仕組みができあがります!
顧客管理機能の実装
認証機能が実装できたので、顧客管理機能を追加します。
Model
customersテーブルを作成する。
CREATE TABLE customers (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(20) NOT NULL,
last_name VARCHAR(20) NOT NULL,
telephone_number VARCHAR(20) NOT NULL,
mailaddress VARCHAR(50) NOT NULL,
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
);
CustomersTableクラスを定義するため、src/Model/Table/CustomersTable.php
を作成する。
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class CustomersTable extends Table
{
public function validationDefault(Validator $validator)
{
return $validator
->notEmpty('first_name', 'First name is required')
->notEmpty('last_name', 'Last name is required');
}
}
Customerクラスのエンティティを定義するため、src/Model/Entity/Customer.php
を作成する。
<?php
namespace App\Model\Entity;
use Cake\ORM\Entity;
class Customer extends Entity
{
protected $_accessible = [
'*' => true,
'id' => false
];
}
Controller
CustomersControllerを定義するため、src/Controller/CustomersController.php
を作成する。
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
class CustomersController extends AppController
{
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
}
public function isAuthorized($user)
{
return true;
}
public function index()
{
$this->set('customers', $this->Customers->find('all'));
}
public function view($id)
{
$customer = $this->Customers->get($id);
$this->set(compact('customer'));
}
public function add()
{
$customer = $this->Customers->newEntity();
if ($this->request->is('post')) {
$customer = $this->Customers->patchEntity($customer, $this->request->data);
if ($this->Customers->save($customer)) {
$this->Flash->success(__('The customer has been saved.'));
return $this->redirect(['action' => 'add']);
}
$this->Flash->error(__('Unable to add the customer.'));
}
$this->set('customer', $customer);
}
}
View
顧客登録画面のテンプレートを定義するため、src/Template/Customers/add.ctp
を作成する。
<div class="customers form">
<?= $this->Form->create($customer) ?>
<fieldset>
<legend><?= __('Add Customer') ?></legend>
<?= $this->Form->input('first_name') ?>
<?= $this->Form->input('last_name') ?>
<?= $this->Form->input('telephone_number') ?>
<?= $this->Form->input('mailaddress') ?>
</fieldset>
<?= $this->Form->button(__('Submit')); ?>
<?= $this->Form->end() ?>
</div>
顧客一覧画面のテンプレートを定義するため、src/Template/Customers/index.ctp
を作成する。
<h1>Customers</h1>
<table>
<tr>
<th>Id</th>
<th>First name</th>
<th>Last name</th>
</tr>
<?php foreach ($customers as $customer): ?>
<tr>
<td><?= $this->Html->link($customer->id, ['action' => 'view', $customer->id]) ?></td>
<td><?= $customer->first_name ?></td>
<td><?= $customer->last_name ?></td>
</tr>
<?php endforeach; ?>
</table>
顧客詳細画面のテンプレートを定義するため、src/Template/Customers/view.ctp
を作成する。
<h1><?= h($customer->id) ?></h1>
<p><?= h($customer->first_name) ?></p>
<p><?= h($customer->last_name) ?></p>
<p><?= h($customer->telephone_number) ?></p>
<p><?= h($customer->mailaddress) ?></p>
注文管理機能の実装
顧客管理機能が実装できたので、さらに顧客からの注文を管理する機能を追加します。
Model
requestsテーブルを作成する。
1人の顧客が複数の注文をできるという要件で実装してみるため、requestsテーブルにcustomer_idを持たせて、外部キーを設定します。
CREATE TABLE requests (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
customer_id INT UNSIGNED NOT NULL,
created DATETIME,
modified DATETIME,
FOREIGN KEY customer_key (customer_id) REFERENCES customers(id)
);
RequestsTableクラスを定義するため、src/Model/Table/RequestsTable.php
を作成する。
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class RequestsTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('Timestamp');
}
}
Controller
RequestsControllerを定義するため、src/Controller/RequestsController.php
を作成する。
<?php
namespace App\Controller;
class RequestsController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('Flash'); // Include the FlashComponent
}
public function isAuthorized($user)
{
return true;
}
public function index()
{
$requests = $this->Requests->find('all');
$this->set(compact('requests'));
}
public function view($id = null)
{
$request = $this->Requests->get($id);
$this->set(compact('request'));
}
public function add()
{
$request = $this->Requests->newEntity();
if ($this->request->is('post')) {
$request = $this->Requests->patchEntity($request, $this->request->query);
if ($this->Requests->save($request)) {
$this->Flash->success(__('Your request has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Unable to add your request.'));
}
$this->set('request', $request);
}
}
顧客詳細画面に注文のリストを表示するため、CustomersControllerのviewメソッドを修正する。
use Cake\ORM\TableRegistry;
・
・
・
public function view($id = null)
{
$customer = $this->Customers->get($id);
$this->set(compact('customer'));
$requests = TableRegistry::get('Requests');
$this->set('requests', $requests->find('all'));
}
View
注文登録画面のテンプレートを定義するため、src/Template/Requests/add.ctp
を作成する。
<h1>Add Request</h1>
<?php
echo $this->Form->create($request);
echo $this->Form->button(__('Save Request'));
echo $this->Form->end();
?>
注文一覧画面のテンプレートを定義するため、src/Template/Requests/index.ctp
を作成する。
<h1>requests</h1>
<table>
<tr>
<th>Id</th>
<th>CustomerId</th>
</tr>
<?php foreach ($requests as $request): ?>
<tr>
<td>
<?= $this->Html->link($request->id, ['action' => 'view', $request->id]) ?>
</td>
<td>
<?= $this->Html->link($request->customer_id, ['controller' => 'customers', 'action' => 'view', $request->customer_id]) ?>
</td>
</tr>
<?php endforeach; ?>
</table>
注文詳細画面のテンプレートを定義するため、src/Template/Requests/view.ctp
を作成する。
<h1><?= h($request->id) ?></h1>
<p>CustomerId: <?= h($request->customer_id ?></p>
さらに顧客詳細画面のテンプレートに、その顧客に属する注文リストを追加する。
<h1><?= h($customer->title) ?></h1>
<p>FirstName: <?= h($customer->first_name) ?></p>
<p>LastName: <?= h($customer->last_name) ?></p>
<p>TelephoneNumber: <?= h($customer->telephone_number) ?></p>
<p>Mailaddress: <?= h($customer->mailaddress) ?></p>
<p><?= $this->Html->link('Add Request', ['controller' => 'requests', 'action' => 'add', '?' => ['customer_id' => $customer->id]]) ?></p>
<p>requests</p>
<table>
<tr>
<th>Id</th>
</tr>
<?php foreach ($requests as $request): ?>
<tr>
<td> <?= $this->Html->link($request->id, ['action' => 'view', $request->id]) ?> </td>
</tr>
<?php endforeach; ?>
</table>
こちらの記事を参考にすすめていくと、簡単に管理機能の実装ができあがります。
Blog Tutorial part2
Blog Tutorial part3
今後も引き続き追加していきます。。。