-----
Phần x36. CakePHP2
– beforeValidate, unset, cập nhật thông tin user
Xem (clip số 37 – chickenrainshop):
Hàm callback là các hàm được gọi để xử lý một số tác vụ cụ
thể trên model hoặc controller. Hàm callback là hàm chạy ngầm (chạy trước hoặc
sau một hàm/thao tác khác) được gọi bởi thao tác khác trong model hoặc
controller.
Một số hàm callback:
Trên model
|
Trên controller
|
Hàm callback được gọi trước hoặc sau các thao tác: find,
save, update, delete, validate.
|
Hàm callback được gọi trước hoặc sau các action.
|
Ví dụ: beforeFind(), afterFind(), beforeSave(),
afterSave(), beforeDelete(), afterDelete(), beforeValidate()
|
Ví dụ: beforeFilter(), afterFilter(), beforeRender(),
afterRender(), beforeRedirect()
|
Xem (clip số 38 – chickenrainshop):
- Cập nhật thông tin người dùng đã đăng nhập (38)
- findById (4":39)
- Hàm unset (12":13)
Cập nhật thông tin người dùng:
Tạo link cho mục ‘Cập nhật thông tin’ trong layout
default.ctp:
userInfo['fullname']; ?></strong></small></h4>
<ul>
<li><?php echo
$this->Html->link('Cập nhật thông tin', '/cap-nhat-thong-tin');
?></li>
<li><?php
echo $this->Html->link('Đổi mật khẩu', '/doi-mat-khau'); ?></li>
Thực hiện cắt đoạn mã hiển thị các chức năng liên quan đến
user trong default.ctp, đưa vào element có tên là user_panel.ctp.
[Elements\user_panel.ctp]
<?php if (!empty($userInfo)): ?>
<div
class="panel panel-info">
<h4
class="panel-heading"><span class="glyphicon
glyphicon-user"></span><small> Xin chào
<strong><?php echo $userInfo['fullname'];
?></strong></small></h4>
<ul>
<li><?php
echo $this->Html->link('Cập nhật thông tin', '/cap-nhat-thong-tin');
?></li>
<li><?php
echo $this->Html->link('Đổi mật khẩu', '/doi-mat-khau'); ?></li>
<li><a
href="">Lịch sử mua hàng</a></li>
<li><?php
echo $this->Html->link('Đăng xuất', '/logout'); ?></li>
</ul>
</div>
<?php else: ?>
<div
class="panel panel-info">
<h4
class="panel-heading"><span class="glyphicon
glyphicon-user"></span><small> Xin chào
<strong>khách</strong></small></h4>
Nhấn
vào <?php echo $this->Html->link('đây','/login'); ?> để đăng
nhập.<br>
Nếu
bạn chưa có tài khoản hãy đăng ký tại <?php echo
$this->Html->link('đây', '/dang-ky') ?>.
</div>
<?php endif ?>
Trong layout default.ctp, thêm đoạn mã gọi element
user_panel.ctp:
<div class="sidebar col col-lg-3">
<!-- user
panel -->
<?php echo
$this->element('user_panel'); ?>
<!-- /user
panel -->
<div
class="panel panel-info">
<h4
class="panel-heading"><span class="glyphicon
glyphicon-shopping-cart"></span>Giỏ hàng</h4>
Trong UsersController.php, viết action changeInfo():
[UserController.php]
public function changeInfo() {
$this->set('title_for_layout',
'Cập nhật thông tin');
}
Trong routes.php, thực hiện route cho link
/cap-nhat-thong-tin
[routes.php]
Router::connect('/doi-mat-khau', ['controller' => 'users',
'action' => 'changePassword']);
Router::connect('/cap-nhat-thong-tin',
['controller' => 'users', 'action' => 'changeInfo']);
Router::connect('/dang-ky', ['controller' => 'users', 'action'
=> 'register']);
Trong View\Users, tạo view có tên change_info.ctp:
<div class="panel panel-info">
<h4
class="panel-heading"><span class="glyphicon
glyphicon-user"> Cập nhật thông tin</span></h4>
<?php
echo $this->Flash->render(); ?>
<?php
echo $this->Form->create('User', ['class' => 'form-horizontal',
'novalidate' => true, 'inputDefaults' => ['label' => false]]); ?>
<div
class="control-group">
<label
class="control-label" for="inputLastName">Last
Name</label>
<div
class="controls">
<?php
echo $this->Form->input('lastname', ['placeholder' => 'Họ']); ?>
</div>
</div>
<div
class="control-group">
<label
class="control-label" for="inputFirstName">First
Name</label>
<div
class="controls">
<?php
echo $this->Form->input('firstname', ['placeholder' => 'Tên', 'type'
=> 'text']); ?>
</div>
</div>
<div
class="control-group">
<label
class="control-label"
for="inputEmail">Email</label>
<div
class="controls">
<?php
echo $this->Form->input('email', ['placeholder' => 'Địa chỉ email',
'type' => 'text']); ?>
</div>
</div>
<div
class="control-group">
<label
class="control-label"
for="inputAddress">Address</label>
<div
class="controls">
<?php
echo $this->Form->input('address', ['placeholder' => 'Địa chỉ', 'type'
=> 'text', 'error' => false]); ?>
</div>
</div>
<div
class="control-group">
<label
class="control-label"
for="inputPhone">Phone</label>
<div
class="controls">
<?php
echo $this->Form->input('phone_number', ['placeholder' => 'Số điện
thoại', 'type' => 'number', 'error' => false]); ?>
</div>
</div>
<div
class="control-group">
<div
class="controls">
<?php
echo $this->Form->button('Cập nhật', ['type' => 'submit', 'class'
=> 'col-lg-2 btn btn-primary']); ?>
</div>
</div>
<?php
echo $this->Form->end(); ?>
</div>
Để lấy thông tin người dùng dựa vào id, sử dụng hàm
findById(‘id’). Ví dụ:
// lấy thông tin người dùng, hiển thị lên form
$this->request->data =
$this->User->findById($userInfo['id']);
Viết tiếp action changeInfo():
/**
* thay đổi thông tin người
dùng
*/
public function
changeInfo() {
$userInfo
= $this->getUser();
if
($this->request->is('put') || $this->request->is('post')) {
$this->User->set($this->request->data);
if
($this->User->Validates()) {
$data
= [
'lastname'
=> $this->request->data['User']['lastname'],
'firstname'
=> $this->request->data['User']['firstname'],
'email'
=> $this->request->data['User']['email'],
'email'
=> $this->request->data['User']['email'],
'phone_number'
=> $this->request->data['User']['phone_number'],
'address'
=> $this->request->data['User']['address']
];
$this->User->id
= $userInfo['id'];
if
($this->User->save($data)) {
$this->Flash->success('Đã
lưu thành công!', ['params' => ['class' => 'alert alert-success']]);
}
else {
$this->Flash->error('Có
lỗi xảy ra, vui lòng thử lại!', ['params' => ['class' => 'alert
alert-error']]);
}
}
}
else {
//
lấy thông tin người dùng, hiển thị lên form
$this->request->data
= $this->User->findById($userInfo['id']);
}
$this->set('title_for_layout',
'Cập nhật thông tin');
}
Khắc phục lỗi liên quan đến trường email, khi người dùng bấm
nút ‘Cập nhật’ lần đầu thành công rồi, lại tiếp tục bấm thêm nữa, sẽ sinh ra
lỗi bị trùng email. Lỗi này xảy ra do trong ràng buộc dữ liệu có yêu cầu email
phải là duy nhất.
Viết hàm callback beforeValidate để xử lý lỗi này, ý tưởng
là kiểm tra để đảm bảo dữ liệu người dùng muốn cập nhật và dữ liệu có sẵn trong
cơ sở dữ liệu là như nhau, khi đó sử dụng hàm unset để gỡ bỏ trường dữ liệu
tương ứng khi người dùng gửi lên (ví dụ email), kết quả là trường này bị rỗng
và không thực hiện xác thực dữ liệu cho nó.
[Model\User.php]
// gỡ bỏ trường email trước khi validate
public function beforeValidate($options = array()) {
if
(isset($this->data['User']['email'])) {
//
lấy thông tin người dùng đang đăng nhập
$userInfo
= AuthComponent::user();
//
lấy thông tin của người dùng hiện tại từ cơ sở dữ liệu
$user
= $this->findById($userInfo['id']);
if
(!empty($userInfo) && ($this->data['User']['email'] ==
$user['User']['email'])) {
//
gỡ bỏ trường email
unset($this->data['User']['email']);
}
}
return true;
}
-----------
Cập nhật 7/7/2017
-----------