Ngu ngơ học làm web (x17) - CakePHP2 - Search trên hai table, paginate, validate

Tiếp theo của: Ngu ngơ học làm web (x16) - CakePHP2 – Search trên một table
-----

Phần x17. CakePHP2 – Search trên hai table, paginate, validate


Xem (clip số 22b – chickenrainshop):

Phần này sẽ thực hiện tìm kiếm mở rộng, nghĩa là cho phép người dùng nhập vào một từ khóa, từ khóa này có thể là (một phần) tên một cuốn sách hoặc (một phần) tên của tác giả, và kết quả trả về là cuốn sách có tên hoặc tác giả liên quan.

Câu lệnh truy vấn được thực hiện trên model Book, tuy nhiên cần phải truy vấn đến tên tác giả, nên phải kết nối tới model Writer, việc kết nối giữa Book và Writer được thực hiện thông qua bảng trung gian books_writers, sử dụng từ khóa joins.


[hàm search() trong BooksController.php] thay đổi như sau:

public function search() {
                        $notFound = false;
                        if ($this->request->is('post')) {
                                    $keyword = $this->request->data['Book']['keyword'];
                                    $books = $this->Book->find('all',
                                                [
                                                            'fields' => ['title', 'image', 'sale_price', 'slug'],
                                                            // 'contain' => ['Writer.name', 'Writer.slug'],
                                                            'contain' => ['Writer' => ['name', 'slug']],
                                                            'order' => ['Book.created' => 'desc'],
                                                            'conditions' => [
                                                                        'published' => 1,
                                                                        'or' => [
                                                                                    'title like' => '%'.$keyword.'%',
                                                                                    'w.name like' => '%'.$keyword.'%'
                                                                                    ]
                                                                        ],
                                                            'joins' => [
                                                                        [
                                                                                    'table' => 'books_writers',
                                                                                    'alias' => 'bw',
                                                                                    'conditions' => 'bw.book_id = Book.id'
                                                                        ],
                                                                        [
                                                                                    'table' => 'writers',
                                                                                    'alias' => 'w',
                                                                                    'conditions' => 'bw.writer_id = w.id'
                                                                        ]
                                                            ]
                                                ]);
                                    if (!empty($books)) {
                                                $this->set('results', $books);
                                    } else {
                                                $notFound = true;
                                    }
                        }
                        $this->set('notFound', $notFound);
            }

Phân trang dữ liệu tìm kiếm được.

[hàm search() trong BooksController.php] thay đổi như sau:

public function search() {
                        $notFound = false;
                        if ($this->request->is('post')) {
                                    $keyword = $this->request->data['Book']['keyword'];
                                    $this->paginate = [
                                                            'fields' => ['title', 'image', 'sale_price', 'slug'],
                                                            // 'contain' => ['Writer.name', 'Writer.slug'],
                                                            'contain' => ['Writer' => ['name', 'slug']],
                                                            'order' => ['Book.created' => 'desc'],
                                                            'conditions' => [
                                                                        'published' => 1,
                                                                        'or' => [
                                                                                    'title like' => '%'.$keyword.'%',
                                                                                    'w.name like' => '%'.$keyword.'%'
                                                                                    ]
                                                                        ],
                                                            'joins' => [
                                                                        [
                                                                                    'table' => 'books_writers',
                                                                                    'alias' => 'bw',
                                                                                    'conditions' => 'bw.book_id = Book.id'
                                                                        ],
                                                                        [
                                                                                    'table' => 'writers',
                                                                                    'alias' => 'w',
                                                                                    'conditions' => 'bw.writer_id = w.id'
                                                                        ]
                                                            ]
                                                ];
                                    $books = $this->paginate('Book');
                                    if (!empty($books)) {
                                                $this->set('results', $books);
                                    } else {
                                                $notFound = true;
                                    }
                        }
                        $this->set('notFound', $notFound);
            }

Trong search.ctp thêm dòng mã sau:

<?php if(isset($results) && $notFound == false): ?>
                        <?php echo $this->element('book', ['books' => $results]); ?>
                        <?php echo $this->element('pagination', ['object' => 'quyển sách']); ?>

Thiết lập kiểm tra dữ liệu cho trường ‘keyword’:

[Model\Book.php]

public $validate = array(
                        'keyword' => array(
                                    'rule' => 'notBlank',
                                    'message' => 'Bạn phải nhập từ khóa để tìm kiếm!'
                        ),
                        'title' => array(
                                    'notBlank' => array(

[View\Books\search.ctp]

<?php echo $this->Form->create('Book', ['novalidate' => true]) ?>
            <?php echo $this->Form->input('keyword',
                        [
                                    'label' => '',
                                    'placeholder' => 'Nhập từ khóa tìm kiếm...',
                                    'error' => false,
                                    'required' => false
                        ]);
            ?>
            <?php if (isset($errors)): ?>
                        <?php foreach ($errors as $error): ?>
                                    <?php echo $error[0]; ?>
                        <?php endforeach ?>
            <?php endif ?>
            <?php if (isset($results) && $notFound == false): ?>
                        <?php echo $this->element('book', ['books' => $results]); ?>
                        <?php echo $this->element('pagination', ['object' => 'quyển sách']); ?>
            <?php elseif($notFound == true): ?>
                        Không tìm thấy quyển sách này!
            <?php endif ?>
<?php echo $this->Form->end('Search'); ?>

[Controller\BooksController.php search()]

public function search() {
                        $notFound = false;
                        if ($this->request->is('post')) {
                                    $this->Book->set($this->request->data);
                                    if ($this->Book->validates()) {
                                                $keyword = $this->request->data['Book']['keyword'];
                                                $this->paginate = [
                                                                        'fields' => ['title', 'image', 'sale_price', 'slug'],
                                                                        // 'contain' => ['Writer.name', 'Writer.slug'],
                                                                        'contain' => ['Writer' => ['name', 'slug']],
                                                                        'order' => ['Book.created' => 'desc'],
                                                                        'conditions' => [
                                                                                    'published' => 1,
                                                                                    'or' => [
                                                                                                'title like' => '%'.$keyword.'%',
                                                                                                'w.name like' => '%'.$keyword.'%'
                                                                                                ]
                                                                                    ],
                                                                        'joins' => [
                                                                                    [
                                                                                                'table' => 'books_writers',
                                                                                                'alias' => 'bw',
                                                                                                'conditions' => 'bw.book_id = Book.id'
                                                                                    ],
                                                                                    [
                                                                                                'table' => 'writers',
                                                                                                'alias' => 'w',
                                                                                                'conditions' => 'bw.writer_id = w.id'
                                                                                    ]
                                                                        ]
                                                            ];
                                                $books = $this->paginate('Book');
                                                if (!empty($books)) {
                                                            $this->set('results', $books);
                                                } else {
                                                            $notFound = true;
                                                }
                                    } else {
                                                $errors = $this->Book->validationErrors;
                                                $this->set('errors', $errors);
                                    }
                        }
                        $this->set('notFound', $notFound);
            }

Để không hiển thị thông báo lỗi validate mặc định ngay dưới một input, thêm thuộc tính 'error' => false, ví dụ:

<?php echo $this->Form->input('keyword',
                        [
                                    'label' => '',
                                    'placeholder' => 'Nhập từ khóa tìm kiếm...',
                                    'error' => false
                        ]);

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