--------------- <> -----------------
--- KHOA HỌC - CÔNG NGHỆ - GIÁO DỤC - VIỆC LÀM ---
--- Học để đi cùng bà con trên thế giới ---

Tìm kiếm trong Blog

Ngu ngơ học làm web (x40) - CakePHP2 - forgot password, generate code

Tiếp theo của: Ngu ngơ học làm web (x39) - CakePHP2 – Sách bán chạy
-----

Phần x40. CakePHP2 – forgot password, generate code


Xem (clip số 41a– chickenrainshop):

Viết chức năng ‘quên mật khẩu’ (forgot password).

- Xử lý quên mật khẩu (41a)

- Hàm sinh mã generate_code (10":09)

- Xác nhận qua email (12":12)

Quy trình xử lý của chức năng ‘quên mật khẩu’:

Bước 1: Điền email
Bước 2: Xác nhận
Bước 3: Đổi mật khẩu mới
- Tạo form
- Kiểm tra email
- Gửi xác nhận
- Kiểm tra xác nhận
- Hiện form đổi mật khẩu
- Kiểm tra mật khẩu
- Lưu mật khẩu mới

Tạo link để vào trang ‘quên mật khẩu’:

[View\Users\login.ctp]

<div class="controls">
            <?php echo $this->Form->button('Đăng nhập', ['type' => 'submit', 'class' => 'col-lg-2 btn btn-primary']); ?>
            <?php echo $this->Html->link('Bạn quên mật khẩu?', '/quen-mat-khau'); ?>
</div>

Viết route cho link ‘/quen-mat-khau’:

[routes.php]

Router::connect('/sach-moi', ['controller' => 'books', 'action' => 'latest_books']);
Router::connect('/quen-mat-khau', ['controller' => 'users', 'action' => 'forgotPassword']);
Router::connect('/sach-ban-chay', ['controller' => 'books', 'action' => 'bestSelling']);

Viết action forgotPassword():

[UsersController.php]

public function forgotPassword() {
                        $this-set('title_for_layout', 'Quên mật khẩu');
            }

Viết view forgot_password.ctp:

[View\Users\forgot_password.ctp]

<div class="panel panel-info">
            <h4 class="panel-heading"><span class="glyphicon glyphicon-user"></span> Quên mật khẩu</h4>
            <?php echo $this->Flash->render('forgot'); ?>
            <?php echo $this->Form->create('User', ['class' => 'form-horizontal', 'novalidate' => true, 'inputDefaults' => ['label' => false]]); ?>
                        <div class="control-group">
                                    <label class="control-label" for="inputEmail">Email</label>
                                    <div class="controls">
                                                <?php echo $this->Form->input('email', ['placeholder' => 'Điền email của bạn']); ?>
                                    </div>
                        </div>
                        <hr>
                        <div class="control-group">
                                    <div class="controls">
                                    <?php echo $this->Form->button('Cấp lại mật khẩu', ['type' => 'submit', 'class' => 'col-lg-2 btn btn-primary']); ?>
                                    </div>
                        </div>
            <?php echo $this->Form->end(); ?>
</div>

Cho phép action forgotPassword được chạy mà không cần đăng nhập:

[Controller\AppController.php]

public function beforeFilter() {
                        $this->Auth->allow('menu', 'index', 'register', 'forgotPassword');
                        $this->set('userInfo', $this->getUser());
            }

Trong bảng users, tạo thêm trường code, Type: VARCHAR(255), cho phép null.

Viết tiếp action forgotPassword():

            public function forgotPassword() {
                        $this->set('title_for_layout', 'Quên mật khẩu');
                        if ($this->request->is('post')) {
                                    $user = $this->User->findByEmail($this->request->data['User']['email']);
                                    if (!empty($user)) {
                                                // tạo mã xác thực
                                                $code = $this->Tool->generateCode();
                                                // tạo link để người dùng bấm vào
                                                $linkConfirm = 'http://local.chickenrainshop/xac-nhan/'.$code;
                                                // lưu code vào cơ sở dữ liệu
                                                $this->User->id = $user['User']['id'];
                                                $this->User->saveField('code', $code);
                                                $this->Flash->success('Vui lòng kiểm tra hộp thư để xác nhận yêu cầu - '.$linkConfirm, ['params' => ['class' => 'alert alert-success'], 'key' => 'forgot']);
                                    } else {
                                                $this->Flash->error('Email này chưa được đăng kí trên hệ thống', ['params' => ['class' => 'alert alert-error'], 'key' => 'forgot']);
                                    }
                        }
            }

Hàm generateCode() trong [Controller\Component\ToolComponent.php]

public function generateCode() {
                                    $randomNumber = rand(1000000, 9999999);
                                    $code = md5($randomNumber);
                                    return $code;
                        }

Xem (clip số 41b– chickenrainshop):

- Xác thực yêu cầu đổi mật khẩu qua email (41b)

Viết chức năng xác nhận yêu cầu đổi mật khẩu:

[Controller\UsersController.php]

public function confirm($code = null) {
                        $confirm = false;
                        if (!empty($code)) {
                                    $user = $this->User->findByCode($code);
                                    if (!empty($user)) {
                                                $confirm = true;
                                    }
                        }
                        $this->set('confirm', $confirm);
                        $this->set('title_for_layout', 'Yêu cầu đổi mật khẩu mới');
            }

Tạo view cho action confirm():

[View\Users\confirm.ctp]

<div class="panel panel-info">
            <?php if ($confirm): ?>
                        <h4 class="panel-heading"><span class="glyphicon glyphicon-user"> Đổi mật khẩu mới</span></h4>
                        <?php echo $this->element('errors'); ?>
                        <?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="inputUsername">Mật khẩu mới</label>
                                    <div class="controls">
                                                <?php echo $this->Form->input('password', ['placeholder' => 'Nhập mật khẩu mới', 'error' => false]); ?>
                                    </div>
                        </div>
                        <div class="control-group">
                                    <label class="control-label" for="inputPassword">Xác nhận mật khẩu</label>
                                    <div class="controls">
                                                <?php echo $this->Form->input('confirmPassword', ['placeholder' => 'Xác nhận mật khẩu', 'type' => 'password', 'error' => false]); ?>
                                    </div>
                        </div>
                        <div class="control-group">
                                    <div class="controls">
                                                <?php echo $this->Form->button('Lưu', ['type' => 'submit', 'class' => 'col-lg-2 btn btn-primary']); ?>
                                    </div>
                        </div>
                        <?php echo $this->Form->end(); ?>
            <?php else: ?>
                        Xác nhận sai!
            <?php endif ?>
</div>

Cho phép chức năng confirm được thực thi mà không phải đăng nhập:

[Controller\AppController.php]

public function beforeFilter() {
                        $this->Auth->allow('confirm','menu', 'index', 'register', 'forgotPassword');
                        $this->set('userInfo', $this->getUser());
            }

Route cho link confirm:

[routes.php]


Router::connect('/xac-nhan/:code', ['controller' => 'users', 'action' => 'confirm'], ['pass' => ['code']]);
-----------
Cập nhật 22/7/2017
-----------
Xem thêm:
- Tổng hợp các bài viết về Ngu ngơ học làm web

Ngu ngơ học làm web (x39) - CakePHP2 - Sách bán chạy

Tiếp theo của: Ngu ngơ học làm web (x38) - CakePHP2 – routes có tham số, lịch sử mua hàng
-----

Phần x39. CakePHP2 – Sách bán chạy


Xem (clip số 40bt – chickenrainshop):

Hiển thị ‘sách bán chạy’.

Thêm trường ‘hot’ cho bảng books, với Type (tinyint), NULL, default = 0. Cuốn sách nào có trường ‘hot’ bằng 1 là sách bán chạy.

Vào routes.php kiểm tra thấy: Router::connect('/', ['controller' => 'books', 'action' => 'index']);, nghĩa là nội dung của trang chủ sẽ là nội dung của view Books\index.ctp.

Vào view Books\index.ctp thêm vào đoạn mã sau vào cuối tập tin:

[index.ctp]

<div class="panel">
            <h4 class="panel-heading">
                        <span class="glyphicon glyphicon-bookmark">
                                    Sách bán chạy
                                    <?php echo $this->Html->link('(xem tất cả »)', '/sach-ban-chay', [
                                                'class' => 'more'
                                    ]); ?>
                        </span>
            </h4>
            <?php //echo $this->element('book', ['books' => $books]); ?>
</div>

Vào Model\Book.php viết hàm trả về ngẫu nhiên 4 cuốn sách bán chạy.

[Model\Book.php]

public function hot() {
                        return $this->find('all', [
                                    'fields' => ['id', 'title', 'image', 'sale_price', 'slug'],
                                    'conditions' => ['published' => 1, 'hot' => 1],
                                    'order' => 'rand()',
                                    'limit' => 4,
                                    'contain' => ['Writer' => ['fields' => ['name', 'slug']]]
                                    ]);
            }

Vào Controller\BooksController.php sửa lại mã của hàm index():

[Controller\BooksController.php]

public function index() {
                        $books = $this->Book->latest();
                        $hotBooks = $this->Book->hot();
                        $this->set(compact('books','hotBooks'));
                        $this->set('title_for_layout', 'Trang chủ - chickenrainshop');
            }

Vào lại view Books\index.ctp sửa lại mã như sau:

</span>
            </h4>
            <?php echo $this->element('book', ['books' => $hotBooks]); ?>
</div>

Đã xong phần giao diện của trang chủ, giờ sẽ viết cho chức năng: khi người dùng bấm vào ‘Sách bán chạy (xem tất cả)’ hoặc mục ‘Sách bán chạy’ ở menu phía đầu trang, thì sẽ hiển thị ngẫu nhiên 20 cuốn sách bán chạy và không phân trang.

Viết link để tới trang ‘sách bán chạy’:

[Layouts\default.ctp]

<li class="active"><?php echo $this->Html->link('Sách mới', '/sach-moi') ?></li>
<li><?php echo $this->Html->link('Sách bán chạy', '/sach-ban-chay'); ?></li>
<li><a href="#lien-he">Liên hệ</a></li>

Viết route cho link ‘/sach-ban-chay’:

[routes.php]

Router::connect('/sach-moi', ['controller' => 'books', 'action' => 'latest_books']);
Router::connect('/sach-ban-chay', ['controller' => 'books', 'action' => 'bestSelling']);
Router::connect('/login', ['controller' => 'users', 'action' => 'login']);

Viết action bestSelling:

[BooksController.php]

/**
* hiển thị 20 cuốn sách bán chạy
*/
            public function bestSelling() {
                        $hotBooks = $this->Book->hot(20);
                        $this->set('hotBooks', $hotBooks);
                        $this->set('title_for_layout', 'Sách bán chạy');
            }

Sửa lại một chút hàm hot() trong model Book:

[Model\Book.php]

public function hot($limit = null) {
                        return $this->find('all', [
                                    'fields' => ['id', 'title', 'image', 'sale_price', 'slug'],
                                    'conditions' => ['published' => 1, 'hot' => 1],
                                    'order' => 'rand()',
                                    'limit' => $limit,
                                    'contain' => ['Writer' => ['fields' => ['name', 'slug']]]
                                    ]);
            }

Viết view best_selling:

[View\Books\best_selling.ctp]

<div class="panel">
            <h4 class="panel-heading">
                        <span class="glyphicon glyphicon-bookmark"> Sách bán chạy</span>
            </h4>
            <?php echo $this->element('book', ['books' => $hotBooks]); ?>
</div>

Chỉnh lại một chút hàm  beforeFilter() để website không bắt đăng nhập mới vào được trang ‘sách bán chạy’:

[BooksController.php]

public function beforeFilter() {
                        parent::beforeFilter();
                        $this->Auth->allow('view', 'bestSelling');

            }
-----------
Cập nhật 20/7/2017
-----------
Xem thêm:
- Tổng hợp các bài viết về Ngu ngơ học làm web

Ngu ngơ học làm web (x38) - CakePHP2 - routes có tham số, lịch sử mua hàng

Tiếp theo của: Ngu ngơ học làm web (x37) - CakePHP2 – findAllById, TimeFormat, json_decode 
-----

Phần x38. CakePHP2 – routes có tham số, lịch sử mua hàng


Xem (clip số 39b – chickenrainshop):

- Routes có kèm id ví dụ /abc/:id (39b) (1":49)

- Sử dụng loadModel khi truy vấn trong controller (6":56)

Viết chức năng xem chi tiết một đơn hàng.

Tạo link đi đến trang ‘xem chi tiết một đơn hàng’:

[Views\Orders\history.ctp]

<?php else: ?>
<span class="label">Hủy</span>               
<?php endif ?>
</td>
<td><?php echo $this->Html->link('Xem', '/don-hang/'.$order['Order']['id']); ?></td>
</tr>
<?php endforeach ?>

Viết route cho link ‘/don-hang/’ .$order['Order']['id']

[routes.php]

Router::connect('/cap-nhat-thong-tin', ['controller' => 'users', 'action' => 'changeInfo']);
Router::connect('/don-hang/:id', ['controller' => 'orders', 'action' => 'detail'], ['pass'=>['id']]);
Router::connect('/lich-su-mua-hang', ['controller' => 'orders', 'action' => 'history']);

Viết action detail() trong OrdersController.php

[OrdersController.php]

/**
 * xem chi tiết đơn hàng
 *
 */

            public function detail($id = null) {
                        $order = $this->Order->findById($id);
                        if (!empty($order)) {
                                    $userInfo = $this->getUser();
                                    if ($userInfo['id'] == $order['Order']['user_id']) {
                                                $this->set('order', $order);
                                                // cho phép người dùng tải về các cuốn sách họ đã thanh toán
                                                if ($order['Order']['status'] == 1) {
                                                            $books = json_decode($order['Order']['order_info']);
                                                            $this->loadModel('Book');
                                                            foreach ($books as $book) {
                                                                        $this->Book->recursive = -1;
                                                                        $result = $this->Book->findById($book->id);
                                                                        $link[$book->id] = $result['Book']['link_download'];
                                                            }
                                                            $this->set('link', $link);
                                                }
                                    }
                        }
                        $this->set('title_for_layout', 'Xem chi tiết đơn hàng');
            }

Viết mã cho view detail:

[detail.ctp]

<div class="panel panel-info">
            <h4 class="panel-heading"><span class="glyphicon glyphicon-th"></span> Chi tiết đơn hàng</h4>
            <?php if (isset($order)): ?>
                        <?php
                                    $customer_info = json_decode($order['Order']['customer_info']);
                                    $payment_info = json_decode($order['Order']['payment_info']);
                                    $order_info = json_decode($order['Order']['orders_info']);
                        ?>
            <div class="row">
                        <div class="col col-lg-6">
                                    <p><strong>Họ tên người mua hàng: </strong><span><?php echo $customer_info->name; ?></span></p>
                                    <p><strong>Email: </strong><span><?php echo $customer_info->email; ?></span></p>
                                    <p><strong>Điện thoại: </strong><span><?php echo $customer_info->phone; ?></span></p>
                                    <p><strong>Địa chỉ: </strong><span><?php echo $customer_info->address; ?></span></p>
                        </div>
                        <div class="col col-lg-6">
                                    <p><strong>Mã đơn hàng: </strong><span><?php echo $order['Order']['id']; ?></span></p>
                                    <p><strong>Tổng cộng: </strong><span><?php echo $this->Number->currency($payment_info->total, 'VND', ['places'=>0, 'wholePosition'=>'after']); ?></span></p>
                                    <?php if (isset($payment_info->coupon)): ?>
                                                <p><strong>Mã giảm giá: </strong>
                                                            <span>
                                                                        <?php echo $payment_info->coupon; ?> -
                                                                        <strong>Giảm: </strong><?php echo $payment_info->discount; ?>%
                                                            </span>
                                                </p>
                                                <p><strong>Tiền phải trả: </strong><span><?php echo $this->Number->currency($payment_info->pay, 'VND', ['places'=>0, 'wholePosition'=>'after']); ?></span></p>
                                    <?php else: ?>
                                                <p><strong>Tiền phải trả: </strong><span><?php echo $this->Number->currency($payment_info->total, 'VND', ['places'=>0, 'wholePosition'=>'after']); ?></span></p>
                                    <?php endif ?>
                        </div>
            </div>
            <hr>
            Tình trạng đơn hàng:
            <?php if ($order['Order']['status'] == 0): ?>
                        <span class="label label-info">Đang xử lý</span>
            <?php elseif ($order['Order']['status'] == 1): ?>
                        <span class="label label-success">Đã xử lý</span>
            <?php else: ?>
                        <span class="label">Hủy</span>               
            <?php endif ?>
            <hr>
            <h4>Sách đã mua</h4>
            <table class="table table-striped">
                        <thead>
                                    <tr>
                                                <th>STT</th>
                                                <th>Tên sách</th>
                                                <th>Số lượng</th>
                                                <th>Giá</th>
                                                <th>Tải về</th>
                                    </tr>
                        </thead>
                        <tbody>
                                    <?php $i = 1; ?>
                                    <?php foreach ($order_info as $book): ?>
                                                <tr>
                                                            <td><?php echo $i++; ?></td>
                                                            <td><?php $book->title; ?></td>
                                                            <td><?php echo $book->quantity; ?></td>
                                                            <td><?php echo $book->sale_price; ?></td>
                                                            <td>
                                                                        <?php if (isset($link)): ?>
                                                                                    <?php echo $this->Html-link('<i class="glyphicon glyphicon-download"></i> Tải về', $link[$book->id], ['escape' => false]); ?>
                                                                        <?php else: ?>
                                                                                    Chưa xử lý     
                                                                        <?php endif ?>
                                                            </td>
                                                </tr>
                                    <?php endforeach ?>
                        </tbody>
            </table>
<?php else: ?>
            Đơn hàng này không tồn tại!
<?php endif ?>

</div>
-----------
Cập nhật 15/7/2017
-----------
Xem thêm:
- Tổng hợp các bài viết về Ngu ngơ học làm web

Ngu ngơ học làm web (x37) - CakePHP2 - findAllById, TimeFormat, json_decode

Tiếp theo của: Ngu ngơ học làm web (x36) - CakePHP2 – beforeValidate, unset, cập nhật thông tin user
-----

Phần x37. CakePHP2 – findAllById, TimeFormat, json_decode


Xem (clip số 39a – chickenrainshop):

- Hiển thị lịch sử mua hàng của người dùng (39a)

- findAllByUserId (2":59)

- Định dạng thời gian dùng Time->format (6":38)

- Dùng json_decode (7":14)

Tạo link để đi tới trang xem lịch sử mua hàng của người dùng:

[Elements\user_panel.ctp]

<li><?php echo $this->Html->link('Đổi mật khẩu', '/doi-mat-khau'); ?></li>
<li><?php echo $this->Html->link('Lịch sử mua hàng', '/lich-su-mua-hang'); ?></li>
<li><?php echo $this->Html->link('Đăng xuất', '/logout'); ?></li>

Thực hiện route link ‘/lich-su-mua-hang’ về action history của OrdersController:

[routes.php]

Router::connect('/cap-nhat-thong-tin', ['controller' => 'users', 'action' => 'changeInfo']);
Router::connect('/lich-su-mua-hang', ['controller' => 'orders', 'action' => 'history']);
Router::connect('/dang-ky', ['controller' => 'users', 'action' => 'register']);

Viết action history:

Ý tưởng là: duyệt bảng Order, lấy ra các đơn hàng của người dùng.

[OrdersController.php]

/**
 * xem lịch sử mua hàng
 *
 */
public function history() {
            $this->set('title_for_layout', 'Lịch sử mua hàng');
            $userInfo = $this->getUser();
            // lấy các đơn hàng của user
            // - lấy theo id
            // - lấy hết các trường 'null'
            // - sắp xếp theo ngày mua mới nhất
            $orders = $this->Order->findAllByUserId($userInfo['id'], null, ['Order.created' => 'desc']);
            $this->set('orders', $orders);
}

Tạo view history:

[View\Orders\history.ctp]

<div class="panel panel-info">
            <h4 class="panel-heading"><span class="glyphicon glyphicon-th"></span> Lịch sử mua hàng</h4>
            <h4>Dưới đây là toàn bộ thông tin mua hàng của bạn</h4>
<?php echo $this->Flash->render('order'); ?>
            <hr>
            <table class="table table-striped">
                        <thead>
                                    <tr>
                                                <th>STT</th>
                                                <th>Thời gian</th>
                                                <th>Email</th>
                                                <th>Tiền thanh toán</th>
                                                <th>Tình trạng</th>
                                                <th>Chi tiết</th>
                                    </tr>
                        </thead>
                        <tbody>
                                    <?php $i = 1; ?>
                                    <?php foreach ($orders as $order): ?>
                                                <tr>
                                                            <td><?php echo $i++; ?></td>
                                                            <td><?php echo $this->Time->format('d-m-Y H:i:s', $order['Order']['created'], null, 'Asia/Ho_Chi_Minh'); ?></td>
                                                            <td><?php echo json_decode($order['Order']['customer_info'])->email; ?></td>
                                                            <td><?php echo $this->Number->currency(json_decode($order['Order']['payment_info'])->total, 'VND', ['places'=>0, 'wholePosition'=>'after']); ?></td>
                                                            <td><?php if ($order['Order']['status'] == 0): ?>
                                                                                    <span class="label label-info">Đang xử lý</span>
                                                                        <?php elseif ($order['Order']['status'] == 1): ?>
                                                                                    <span class="label label-success">Đã xử lý</span>
                                                                        <?php else: ?>
                                                                                    <span class="label">Hủy</span>               
                                                                        <?php endif ?>
                                                            </td>
                                                            <td><a href="#">Xem</a></td>
                                                </tr>
                                    <?php endforeach ?>
                        </tbody>
            </table>
            <hr>
            <strong>Ghi chú tình trạng đơn hàng</strong>
            <ul>
                        <li>Đã xử lý: đơn hàng đã được chấp nhận</li>
                        <li>Đang xử lý: đơn hàng đang đợi xử lý, bạn vui longf thanh toán cho đơn hàng này</li>
                        <li>Hủy: đơn hàng đã bị hủy, vui lòng liên hệ tại <a href="">đây</a> để biết thêm chi tiết</li>
            </ul>
</div>

Sửa lại một chút mã trong OrdersController.php, action checkout():

$this->Session->delete('payment');
$this->Flash->success('Đang đợi xử lý, vui lòng chuyển khoản để thanh toán đơn hàng của bạn!', ['key' => 'order', 'params' => ['class' => 'alert alert-success']]);
} else {
$this->Flash->error('Thanh toán không thực hiện được!', ['key' => 'order', 'params' => ['class' => 'alert alert-danger']]);
}
            //$this->redirect($this->referer());
            $this->redirect('/lich-su-mua-hang');

}
-----------
Cập nhật 12/7/2017
-----------
Xem thêm:
- Tổng hợp các bài viết về Ngu ngơ học làm web