Trang

Thứ Năm, 18 tháng 7, 2013

Chức năng tìm kiếm trong Zend [Zend Framework]

Tìm kiếm là một chức năng không thể thiếu đối với một trang web, chúng ta cùng xây dựng chức năng tìm kiếm đơn giản trong Zend Framework.
I. Mô hình hoạt động

1. Hình minh họa




2. Hoạt động

- Nếu người dùng không nhập gì hoặc chỉ nhập khoảng trắng, sau đó ấn search thì chuyển về trang chủ. Kết hợp thông báo bằng javascript.

- Nếu không ấn search mà vào thẳng trang kết quả tìm qua đường link trên trình duyệt thì cũng chuyển về trang chủ.

- Từ khóa tìm kiếm được escape để tránh bị lỗi SQL Injection, đồng thời loại bỏ tag html để tránh bị chèn script.

- Kết quả tìm kiếm được phân trang tối ưu; không phải mang dữ liệu từ trang này sang trang khác.

II. Xây dựng chức năng tìm kiếm

Bước 1: Tạo Form tìm kiếm

Vào thư mục default/forms tạo file search.php với nội dung
<?php
class Default_Form_Search extends Zend_Form
 {
   public function init()
    {
      // Ô tìm kiêm
      $this->addElement('text','timkiem',array(
                                              'size'=>50,
                                              ));
          //Submit
      $this->addElement('submit','submit',array(
                                                'label'=>'Search',
                                               ));
      $submit=$this->getElement('submit')->setAttrib('onClick',"javascript: return checkEmpty(); ");
     
    }
 }

Dòng in màu có mục đích khi onClick (submit) thực hiện kiểm tra bằng javascript, nếu người dùng không nhập từ khóa hoặc chỉ nhập khoảng trắng thì hiện thông báo "Vui lòng nhập từ khóa tìm kiếm".

Bước 2: Viết script hiện thông báo với nội dung

function checkEmpty()
 {
     var keyword = document.formSearch.timkiem.value.trim();
      if( keyword == "" )
      {
         alert(" Vui lòng nhập từ khóa tìm kiếm ");
         return false;
      }
     return true;
 }

document.formSearch.timkiem.value.trim(): lấy dữ liệu từ element timkiem , sau đó cắt bỏ khoảng trắng hai đầu. Nếu người dùng chỉ nhập khoảng trắng thì bị cắt bỏ hết. Do vậy mà giá trị thành rỗng.

Bước 3: Nhúng Form tìm kiếm vào trang web

Vì form tìm kiếm lúc nào cũng xuất hiện trên mọi trang nên ta khởi tạo nó trong function init() của Index Controller sau đó truyền qua file formSearch.php - được tạo trong thư mục public/default
// Search
 $formSearch = new Default_Form_Search(array('name'=>'formSearch','id'=>'formSearch',
                                             'action'=>HOST_PATH.'/default/index/kqtim',
                                              'method'=>'post',
                                               ));
 $this->view->formSearch=$formSearch;

Khi submit thì từ khóa tìm kiếm sẽ được chuyển qua kqtimAction để được xử lý, sau đó hiện kết quả.

Ta tạo một file formSearch.php trong thư mục public/default với nội dung
<?php
echo $this->formSearch;
?>

File này chính là Form tìm kiếm của chúng ta, bây giờ ta require nó vào header của default_layout.phtml
<div id="chw_header">

   <?php
     require "box_account.php";
   ?>
            
   <div class="wrap_box_search">
   <?php
      require "formSearch.php";
   ?>
   </div>
            
</div><!--end #chw_header-->

Bước 4: Viết hàm Validate từ khóa tìm kiếm

Trong thư mục forms tao thư mục Validate. Trong thư mục Validate tạo hai file checksql.phpsql_safe.php

checksearch.php:
<?php
require "sql_safe.php";
class Default_Form_Validate_Checksql
 {
   public function getValid($data)
    {
     // Lọc khoảng trắng đầu cuối
     $filter = new Zend_Filter_StringTrim();
     $result = $filter->filter($data);
     
     // Escape dấu nháy đơn, nháy kép, dấu backslash
     $result = sql_escape($result);
     
     // Lọc tag HTML
     $result = loc_html($result);
      
      return $result;
    }
     
 }

sql_safe.php:
<?php
function sql_escape($value)
 {
    
    if(get_magic_quotes_gpc())
      {
          $value=stripcslashes($value);    
      }
      
    if(function_exists("mysql_real_escape_string"))
     {
         $value=mysql_real_escape_string($value);   
     }else{
            $value=addslashes($value);
          }
   return $value;    
     
 }
  
 function loc_html($value)
  {
    return htmlspecialchars($value);  
  }
 
?>

Bước 5: Viết truy vấn cơ sở dữ liệu với từ khóa tìm kiếm
Trong default/models tạo file chitiettin.php với nội dung
<?php
class Default_Model_Chitiettin extends Zend_Db_Table_Abstract 
 {
        protected $_name="chitiettin";
        protected $_primary="idTin";
        protected $_db;
        
       public function __construct()
        {
            $this->_db=Zend_Registry::get('db');
        }

       public function getTinTimKiem($keyword)
          {
                $se=$this->_db->select()
                              ->from('chitiettin',array('idTin','TieuDe','TieuDe_KhongDau','TomTat','UrlHinh','ThuMucHinh','ThuMucHinhRoot','Ngay','ThoiGian'))
                              ->where(" AnHien = '1' ")
                              ->where("TieuDe like '%$keyword%' ")
                              ->order('idTin DESC ');
                              
                return $se;  
             }

}

Ta sử dụng truy vấn với Zend_Db_Select, ta không cần fetchAll dữ liệu, chỉ cần chọn bảng, viết câu truy vấn rồi trả về kết quả. Kết quả này sẽ được Zend_Paginator_Adapter_DbSelect xử lý để tối ưu hóa việc phân trang.

Chú ý: Các tham số đầu vào của câu truy vấn phải để trong nháy đơn, tránh bị SQL Injection. Ví dụ như phía trên
"TieuDe like '%$keyword%' "

Bước 6: Xử lý từ khóa tìm kiếm

Tạo kqtimAction trong IndexController, đây chính là Action mà formSearch sẽ truyền dữ liệu tới
// Search
public function kqtimAction()
{
  $mod = $this->_request->getModuleName();
  
  // Lấy keyword trong link phân trang 
  $keyword=$this->_request->getParam('keyword');
  
  if($this->_request->getPost('submit') || $keyword != "" )
    {
        if( $keyword == "" )
         {
            $keyword=$this->_request->getPost('timkiem');
         } 
            
        $checkSearch = new Default_Form_Validate_Checksql();
        
         $keyword = $checkSearch->getValid($keyword);
         
         if( $keyword !== '')
          {
            $ctt = new Default_Model_Chitiettin();
            $kqtim = $ctt->getTinTimKiem($keyword);
          
             // Phan trang
             $adapter = new Zend_Paginator_Adapter_DbSelect($kqtim);
             $pa = new Zend_Paginator($adapter);
             $pa->setItemCountPerPage(4); 
             $pa->setPageRange(5); 
             $current = $this->_request->getParam('page',1); 
             $pa->setCurrentPageNumber($current);
              
              //view
             $this->view->pa=$pa;
             $this->view->keyword=$keyword;
                          
           }else{
                   $this->_redirect(HOST_PATH."/$mod/index");
                }
        
    }else{
            $this->_redirect(HOST_PATH."/$mod/index");
         }
}
//End Search

- Nếu cố tình vào trang kqtim mà chưa có submit cũng bị chuyển qua index.php

- Nếu người dùng không nhập gì cả hoặc chỉ nhập khoảng trắng (bị validate, khoảng trắng bị xóa nên trở thành rỗng) thì khi có submit thì chuyển qua trang index.php

- Do phân trang, nên mình phải truyền keyword từ trang này sang trang khác để nó hiểu mình đang kiếm gì. Do vậy trên link điều khiển phân trang sẽ có thêm tham số keyword giống như sau:

http://localhost/cunghocweb/index/kqtim/page/3/keyword/zend

Do vậy mà khi ta click vào link điều khiển phân trang thì khi chạy action, đầu tiên ta phải lấy tham số keyword về, trong điều kiện khi submit ta thêm điều kiện keyword mà ta lấy về khác rỗng để khỏi bị chuyển trang về index.php.

Tiếp theo keyword mà ta lấy về mà khác rỗng, tức là ta ấn link điều khiển phân trang, thì nó sẽ tiếp tục tìm kiếm với keyword đó. Còn nếu keyword mà ta lấy về mà rỗng, đồng nghĩa với ta tìm kiếm với từ khóa trên formSearch thì ta sẽ lấy dữ liệu trên form đó.

Bước 7: Truyền kết quả qua View kqtim.phtml

<div class="wrap_kqtim">
  <?php
  foreach($this->pa as $item)
   {
  ?>
  <div class="box_kqtim">
   <h2 class="tieude_kqtim"> <a href="<?php echo HOST_PATH ?>/default/index/chitiettin/tin/<?php echo $item['TieuDe_KhongDau'] ?>"><?php echo $item['TieuDe'] ?></a> </h2>
     
     <div class="tomtat_kqtim">
         <?php echo $item['TomTat']; ?>
     </div>
  </div>
  <?php } ?>
  
  <!--Phan trang-->
  <center>
  <?php
    echo $this->paginationControl($this->pa,'Sliding','control_pa.phtml',array('keyword'=>$this->keyword));  
  ?>
  </center>
</div>

Dòng in màu chính là link điều khiển phân trang của chúng ta. Chú ý, ta phải truyền keyword để các link hiều mình đang kiếm gì

Bước 8: Tạo file điều khiển phân trang

Trong default/views/scripts ta tạo file control_pa.phtml với nội dung

<?php foreach ($this->pagesInRange as $page): ?>
  <?php if ($page != $this->current): ?>
    <a class="tk_page_0" href="<?php echo $this->url(array('page' => $page,'keyword'=>$this->keyword)); ?>">
        <?php echo $page; ?>
    </a> 
  <?php else: ?>
     <span class="disabled_page"><?php echo $page; ?></span> 
  <?php endif; ?>
<?php endforeach; ?>
 
<!-- Next page link -->
<?php if (isset($this->next)): ?>
  <a class="tk_next" href="<?php echo $this->url(array('page' => $this->next,'keyword'=>$this->keyword)); ?>">
    Next &gt;
  </a>
<?php endif; ?>


<!--Last page link-->
<?php if(isset($this->last)): ?>
<a class="tk_pre" href="<?php echo $this->url(array('page'=>$this->last,'keyword'=>$this->keyword)); ?>" > Last </a>
<?php else: ?>
 <span class="disabled" > Last </span>
 <?php endif; ?>

</div>

<?php endif; ?>

Trong mỗi url ta thêm từ khóa vào.

Bước 9: Css cho điều khiển phân trang

/*link phan trang*/
.phantrang{clear:both;margin-top:10px;width:690px}
.paginationControl{overflow:hidden;background-color:#FFF;height:40px;line-height:40px}
.thongke_pa{font-weight:bold;padding:10px 10px 10px 10px;background-color:#06F;color:#FFF;
                border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
            }
.paginationControl a.tk_pre:link, .paginationControl a.tk_pre:visited{background-color: #06F;color:#FFF;font-weight:bold;margin-right:4px ;
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 10px 10px 10px;
    }
.paginationControl a.tk_pre:hover{background-color:#F90;color:#FFF}

.paginationControl a.tk_page_0:link, .paginationControl a.tk_page_0:visited{background-color:#06F;color:#FFF;font-weight:bold;margin-right:4px; 
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 15px 10px 15px;
    }
.paginationControl a.tk_page_0:hover{background-color:#F90;color:#FFF}

.paginationControl a.tk_next:link, .paginationControl a.tk_next:visited{background-color:#06F;color:#FFF;font-weight:bold;margin-right:4px ;
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 15px 10px 15px;
    }
.paginationControl a.tk_next:hover{background-color:#F90;color:#FFF}
.paginationControl .disabled {background-color: #BAD3ED;color:#FFF;font-weight:bold;margin-right:4px ;
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 15px 10px 15px;
    }
.paginationControl .disabled_page {background-color:#BAD3ED;color:#FFF;font-weight:bold;margin-right:4px ;
       border-radius: 5px;
     -moz-border-radius: 5px; 
    -webkit-border-radius: 5px;
    padding:10px 15px 10px 15px;
    }    
    
/*end link phan trang*/
Nguồn: Sưu tầm Internet

2 nhận xét: