Zend\Form cơ bản

Trong Zend Framework, có lớp thư viện Zend\Form dùng để biểu diễn các Form HTML và các phương thức để tương tác dữ liệu, kiểm tra hợp lệ ...

Ứng dụng của bạn phải đảm bảo đã tích hợp Zend\Form, nếu chưa có chạy lệnh composer sau để tích hợp:

composer require zendframework/zend-form

Quy trình sử dụng Zend\Form chuẩn theo sơ đồ dưới đây:

form
Quy trình dùn form - Zend Framewrok

Giải thích các bước trên

Bước 1: Xây dựng Form Model

Bạn xây dựng form với việc đầu tiên là xây dựng một model về form đó, chính là bạn tạo ra một lớp biểu diễn form, lớp này kế thừa từ Zend\Form\Form, sau khi có model thì bạn tạo ra đối tượng của lớp đó.

Ví dụ: tạo một model form

use Zend\Form\Form;

class MyForm extends Form
{
    public function __construct()
    {
        //Định nghĩa tên cho form
        parent::__construct('formname');

        // Set POST method for this form
        $this->setAttribute('method', 'post');

        //Mã thêm các phần tử của form
        //Mã thêm các validator, filter ...

    }
//....
}

Cơ bản các việc bạn cần làm khi tạo ra lớp model form của riêng bạn là:

  • Định nghĩa tên form, thiết lập các thuộc tính như method (post, get), action ... bằng phương thức setAttribute
  • Định nghĩa các phần tử mà form chứa (Text, Button, Radio, Select ...) bằng cách sử dụng phương thức Add, các phần tử của Form có thể biểu diễn bạn xem tại: Các phần tử trong Zend Form
  • Thêm Validator và Filter bằng FilterInput - Thêm các validator để kiểm tra hợp lệ dữ liệu đưa vào các phần tử form mỗi khi người dùng submit, các validator xem tại: Zend Validator. Thêm các filter dữ liệu, để lọc các dữ liệu không phù hợp và chuyển về dạng phù hợp, ví dụ loại bỏ các ký tự đặc biệt của dữ liệu submit ..., các filter bạn xem tại Filter Zend Framework

Lấy một phần tử của form bằng phương thức $form->get('name');

Bước 2: Kiểm tra submit hay không

Cách sử dụng an toàn, đó là sử dụng phương thức POST của các form, tại bước này ở các action của Controller bạn kiểm tra xem có phải dữ liệu được người dùng post đến.

$request = $this->getRequest();
if ($request->isPost()) {
    //Post đến, submit
}

Bước 4: Đọc dữ liệu gửi đến

Việc đọc dữ liệu từ thông tin HTTP Request gửi đến đã trình bày trong phần Đọc dữ liệu từ HTTP Request

//lấy toàn bộ mảng dữ liệu mà form POST đến
$datapost = $this->params()->fromPost();

//lấy toàn bộ mảng dữ liệu từ chuỗi query của URl
$dataget = $this->params()->fromQuery();

Bước 5: Chuyển dữ liệu vào form

Khi đã thu thập được dữ liệu từ HTTP Request, các dữ liệu có thể đưa vào đối tượng form model bằng phương thức $form->bind($object), $form->setData($datapost)

Sử dụng setData. Phương thức này căn cứ theo mảng dữ liệu tham số để thiết lập các giá trị vào các phần tử form, chỉ sổ mảng là tên tương ứng với tên phần tử trong form

Ví dụ thiết lập các biến post đến vào form

$params = $this->params();
$form->setData($params->fromPost());

Ví dụ form model có hai phần tử tên là username, password và thiết kế mã HTML để form cũng post đến hai biến có tên username, password. Cách khác cách trên là:

$params = $this->params();

$dulieu = [
  'username' => $params->fromPost('username'),
  'password' => $params->fromPost('password'),
];
$form->setData($dulieu);

Sử dụng bind($object). Phương thực này dùng cơ chế Hydrate của Zend Framework, nó sẽ tự động lấy ra các thuộc tính của đối tượng lớp $object sau đó điền dữ liệu cùng tên vào phần tử form.

//$data là một đối tượng lớp chứ không phải mảng
$data = new ArrayObject();
//...
$form->bind($data);

Trong bước này, form model có sử dụng các filter để lọc dữ liệu, các filter bạn thêm vào cho từng phần tử.

Bước 6: Kiểm tra hợp lệ của dữ liệu form

Sau khi thiết lập dữ liệu vào form, để lấy được dữ liệu hợp lệ trong tiến trình sử dụng, thì bạn cần có bược kiểm tra dữ liệu hợp lệ. Bước này đơn giản là gọi phương thức $form->isValid(). Bước này form model sẽ sử dụng các validator bạn đã thiết lập cho từng phần tử để kiểm tra, nếu tất cả các phần tử đều có dữ liệu hợp lệ thì hàm trả về true, nếu có 1 phần tử dữ liệu không hợp lệ sẽ trả về false và lúc đó mỗi phần tử lỗi sẽ có thêm dữ liệu báo lỗi.

Bước 6: Đọc dữ liệu từ form

Khi form đã được kiểm tra dữ liệu phù hợp, việc lấy mảng dữ liệu từ form ra đơn giản bằng getData

if ($form->isValid()) {
    $validatedData = $form->getData();
} else {
    //Lấy các thông báo lỗi nếu cần
    $messages = $form->getMessages();
}

Bước 3 và 7: Dựng HTML form trong View

Trong các action có sử dụng Form Model, Form Model có thể truyền đến View như các biến thông thường

$view = new ViewModel(
    [
        'form' => $form,
        //..
    ]
);
//...
return $view;

Sau đó trong View bạn có thể dùng các View Helper hỗ trợ về form khác nhau để dựng HTML. Nhớ là trước khi bắt đầu sử dụng trong View, form cần gọi $form->prepare() để đảm bảo trạng thái của Form sẵn sàng sử dụng.

<?php
    $form = $this->form;
    $form->prepare();
    //...
    //Tạo <form method="..." class="..." action="..."   ...>
    echo echo $this->form()->openTag($form);
?>

    //..Các lệnh render phần tử ...

    //Tạo </form>
    <?=$this->form()->closeTag() ?>

Các View Helper dùng để dựng HTML

Method Chi tiết
Form echo $this->form($form); dựng HTML của toàn bộ form, tất cả các phần tử.
formLabel Dựng mã HTML Label của phần tử: echo $this->formLabel($element);
FormElement Dựng mã HTML của phần tử cụ thể: echo $this->formElement($element);
FormElementErrors Dựng mã HTML thông báo lỗi nếu có: echo $this->formElement($element);
FormRow Dựng mã HTML của phần tử gồm cả Label, thông báo lỗi nếu có ...

Thực hành với Form : Contact V.2

Trở lại ứng dụng ví dụ trước với Contact V.1 (Form Contact V.1), giờ ta tiếp tục code trên dự án đó. Có sử đến Zend\Form nhưng chưa sử dụng đến filter, validator

Tạo Model Form: ContactForm2

module/Application/src/Form/ContactForm2.php

<?php
namespace Application\Form;
use Zend\Form\Form;

class ContactForm2 extends Form
{

    /**
     * ContactForm2 constructor.
     */
    public function __construct()
    {
        //Định nghĩa tên cho form
        parent::__construct('contact-form2');
        // Set POST method for this form
        $this->setAttribute('method', 'post');
        $this->setAttribute('class', 'p-4 bg-light');



        $this->addElements();


    }

    public function setAction($url) {
        $this->setAttribute('action', $url);
        return $this;
    }

    private function addElements()
    {
        //Xem thêm: https://xuanthulab.net/cac-phan-tu-co-ban-cua-zend-form.html

        // Add "email" field
        $this->add([
            'type'  => 'email',
            'name' => 'email',
            'attributes' => [
                'id' => 'email',
                'class' => 'form-control'
            ],
            'options' => [
                'label' => 'Email address',
            ],
        ]);

        // Add "subject" field
        $this->add([
            'type'  => 'text',
            'name' => 'subject',
            'attributes' => [
                'id' => 'subject',
                'class' => 'form-control'

            ],
            'options' => [
                'label' => 'Tiêu đề liên hệ',
            ],
        ]);

        // Add "body" field
        $this->add([
            'type'  => 'textarea',
            'name' => 'body',
            'attributes' => [
                'id' => 'body',
                'class' => 'form-control'

            ],
            'options' => [
                'label' => 'Nội dung',
            ],
        ]);
        // Add "phone" field
        $this->add([
            'type'  => 'text',
            'name' => 'phone',
            'attributes' => [
                'id' => 'phone',
                'class' => 'form-control'

            ],
            'options' => [
                'label' => 'Tel',
            ],
        ]);

        // Add the submit button
        $this->add([
            'type'  => 'submit',
            'name' => 'submit',
            'attributes' => [
                'class' => 'btn btn-warning',

                'value' => 'Gửi liên hệ',
            ],
        ]);
    }

}

Trên đây ta đã định nghĩa một Form Model, các phần tử thêm vào form theo hướng dẫn tại: Các phần tử cơ bản của Zend Form

Tạo action contactTwo sử dụng ContactForm2

module/Application/src/Controller/IndexController.php

//...
  public function contactTwoAction() {

        $form = new \Application\Form\ContactForm2();

        $form->setAction($this->url()->fromRoute('application',
            ['action'=>'contacttwo']));
        $params = $this->params();

        $request = $this->getRequest();

        //Xử lý khi POST
        if ($request->isPost()) {

            $form->setData($params->fromPost());

            //Kiểm tra hợp lệ
            if ($form->isValid()) {
                $data = $form->getData();

                //Code xử lý nhận dự liệu (vào database ..., gửi mail ...)
                //...


                //Thông báo - chuyển hướng sang trang khác
                return $this->alertViewModel('Gửi thành công V.2',
                    'Liên hệ của bạn đã gửi thành công V.2'
                    .json_encode($data));
            }


        }



        $view = new ViewModel(
            [
                'form' => $form
            ]
        );

        return $view;

    }

//...

Tạo template view: contacttow.phtml

module/Application/view/application/index/contacttwo.phtml

<h1>Liên hệ với chúng tôi <small>V.2</small></h1>
<p>Xin hãy nhập đầy đủ thông tin rồi bấm vào
<span class="badge badge-danger">Gửi liên hệ</span></p>

<?php
    $form = $this->form;
    $form->prepare();
?>


<div class="col-md-6 mb-4">
    <?= $this->form()->openTag($form); ?>
    <div class="form-group">
        <?= $this->formLabel($form->get('email')); ?>
        <?= $this->formElement($form->get('email')); ?>
        <?= $this->formElementErrors($form->get('email')); ?>
        <small id="emailHelp" class="form-text text-muted">
        Địa chỉ email của bạn sẽ được giữ riêng tư</small>

    </div>
    <div class="form-group">
        <?= $this->formRow($form->get('subject')); ?>
    </div>
    <div class="form-group">
        <?= $this->formRow($form->get('body')); ?>
    </div>
    <div class="form-group">
        <?= $this->formRow($form->get('phone')); ?>
    </div>

    <?= $this->formElement($form->get('submit')); ?>

    <?= $this->form()->closeTag(); ?>

</div>

Chạy thử với URL: http://localhost/zendform/application/contacttwo

contact