12/08/2018, 00:28

Symfony2: Validators, Forms and Emailing

Symfony là một full-stack MVC framework giúp bạn phát triển website nhanh hơn. Nó cũng có sẵn các best practice giúp website của bạn bảo mật và dễ bảo trì, được áp dụng ngay khi bạn cài đặt framework. Bài viết này sẽ hướng dẫn các bạn sử dụng Bundle, Validator, Form and Setting bundle thông qua ...

Symfony là một full-stack MVC framework giúp bạn phát triển website nhanh hơn. Nó cũng có sẵn các best practice giúp website của bạn bảo mật và dễ bảo trì, được áp dụng ngay khi bạn cài đặt framework.

Bài viết này sẽ hướng dẫn các bạn sử dụng Bundle, Validator, Form and Setting bundle thông qua việc xây dựng trang liên hệ. Bên cạnh đó, ở phần cuối của bài viết sẽ trình bày phần gửi mail cho quản trị viên thông qua trang liên hệ.

Tải về và cài đặt.###

Đầu tiên, bạn có thể tải Symfony2 từ website chính thức của Symfony. Ngoài ra, Symfony2 đã có đầy đủ thông tin về hướng dẫn cài đặt và cấu hình cho Symfony và các yêu cầu chi tiết. Hướng dẫn trên sẽ đề cập đến các gói cần thiết để download, hướng dẫn cài đặt các thư viện thứ 3 cần thiết và hướng dẫn phân quyền cho các thư mục.

Bundles: Symfony2 Building Blocks####

Bundles là 1 phần cơ bản của bất kỳ ứng dụng Symfony2. Trong thực tế Symfony2 framework chính là bundle của chính nó. Bundles cho phép chúng ta tách riêng biệt từng phần để tăng tính sử dụng lại của code. Ngoài ra, mục đích của bundle là đóng gói toàn bộ controllers, model, templates và các phần khác như ảnh và CSS. Chúng ta sẽ tạo một bundle với tên là Blogger.

Tạo bundle###

Symfony2 cung cấp một số tasks để hỗ trợ chúng ta khi thực thi các thao tác chung. Một trong số đó là bundle generator. Để bắt đầu sinh ra bundler generator chạy lệnh sau:

php app/console generate:bundle --namespace=Blogger/BlogBundle --format=yml

Đăng ký bundle.###

Bundle BloggerBlogBundle đã được tạo trong Kernel ở app/AppKernel.php. Symfony2 yêu cầu chúng ta đăng ký tất cả bundle được sử dụng. Có thể một số bundle chỉ được đăng ký cho môi trường dev hoặc test.

// app/AppKernel.php
class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = array(
        // ..
            new BloggerBlogBundleBloggerBlogBundle(),
        );
        // ..

        return $bundles;
    }
    // ..
}

Routing###

Bundle routing sẽ được import vào trong routing chính của ứng dụng.

#app/config/routing.yml
BloggerBlogBundle:
    resource: "@BloggerBlogBundle/Resources/config/routing.yml"
    prefix:   /

Option prefix cho phép bạn ánh xạ toàn bộ BloggerBlogBundle với một prefix. Nếu bạn muốn thay đổi prefix thành /blogger thì sẽ thay đổi prefix: /blogger.

Contact Page: Validators, Forms and Emailing###

Controller.###

Để bắt đầu chúng ta tạo controller cho homepage và template cho nó. Tạo controller ở src/Blogger/BlogBundle/Controller/PageController.php và thêm code như sau:

<?php
// src/Blogger/BlogBundle/Controller/PageController.php

namespace BloggerBlogBundleController;

use SymfonyBundleFrameworkBundleControllerController;

class PageController extends Controller
{
    public function indexAction()
    {
        return $this->render('BloggerBlogBundle:Page:index.html.twig');
    }

    public function contactAction()
    {
        return $this->render('BloggerBlogBundle:Page:contact.html.twig');
    }
}

View###

Tiếp theo tạo template cho action này. Tạp file src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig

{# src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig #}
{% extends 'BloggerBlogBundle::layout.html.twig' %}

{% block title %}Contact{% endblock%}

{% block body %}
    <header>
        <h1>Contact symblog</h1>
    </header>

    <p>Want to contact symblog?</p>
{% endblock %}

Routing###

Chúng ta bắt đầu định nghĩa route cho trang index và contact. Trong BloggerBlogBundle mở file src/Blogger/BlogBundle/Resources/config/routing.yml

# src/Blogger/BlogBundle/Resources/config/routing.yml
BloggerBlogBundle_contact:
    pattern:  /contact
    defaults: { _controller: BloggerBlogBundle:Page:contact }
    requirements:
        _method:  GET|POST

Khi có request url matching với /contact và HTTP method là GET thì sẽ thực thi action contact trong PageController.

Contact Entity###

Tạo một class biểu diễn 1 mẫu contact từ người sử dụng. Có thể bao gồm các thông tin: tên, email, chủ đề và nội dung của contact. Tạo file mới src/Blogger/BlogBundle/Entity/Enquiry.php

<?php
// src/Blogger/BlogBundle/Entity/Enquiry.php

namespace BloggerBlogBundleEntity;

class Enquiry
{
    protected $name;

    protected $email;

    protected $subject;

    protected $body;

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }

    public function getSubject()
    {
        return $this->subject;
    }

    public function setSubject($subject)
    {
        $this->subject = $subject;
    }

    public function getBody()
    {
        return $this->body;
    }

    public function setBody($body)
    {
        $this->body = $body;
    }
}

Form.###

Tiếp theo chúng ta sẽ tạo form. Symfony2 cho phép bạn sử dụng form từ bên ngoài project. Form Component Source đã có thể sử dụng. Chúng ta tạo class AbstractType để trình diễn enquiry form. Sau đó có thể tạo form trực tiếp trong controller mà không phải tạo class riêng. Tuy nhiên, việc tách biệt form ra một class mới làm tăng tính sử dụng lại cho ứng dụng và controller cũng trở lên đơn giản hơn.

Enquiry Type###

<?php
// src/Blogger/BlogBundle/Form/EnquiryType.php

namespace BloggerBlogBundleForm;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilderInterface;

class EnquiryType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('name');
        $builder->add('email', 'email');
        $builder->add('subject');
        $builder->add('body', 'textarea');
    }

    public function getName()
    {
        return 'contact';
    }
}

Tạo form trong controller.###

Bây giờ, chúng ta đã có thực thể Enquiry và EnquiryType. Chúng ta có thể sửa lại action contact như sau:

// src/Blogger/BlogBundle/Controller/PageController.php
public function contactAction()
{
    $enquiry = new Enquiry();
    $form = $this->createForm(new EnquiryType(), $enquiry);

    $request = $this->getRequest();
    if ($request->getMethod() == 'POST') {
        $form->bindRequest($request);

        if ($form->isValid()) {
            // Perform some action, such as sending an email

            return $this->redirect($this->generateUrl('BloggerBlogBundle_contact'));
        }
    }

    return $this->render('BloggerBlogBundle:Page:contact.html.twig', array(
        'form' => $form->createView()
    ));
}

và import thêm namespace để sử dụng thực thể Entity và EnquiryType

// Import new namespaces
use BloggerBlogBundleEntityEnquiry;
use BloggerBlogBundleFormEnquiryType;

Rending the form.###

Chúng ta sửa lại view trang contact và nhúng form contact vào.

{# src/Blogger/BlogBundle/Resources/views/Page/contact.html.twig #}
{% extends 'BloggerBlogBundle::layout.html.twig' %}

{% block title %}Contact{% endblock%}

{% block body %}
    <header>
        <h1>Contact symblog</h1>
    </header>

    <p>Want to contact symblog?</p>

    <form action="{{ path('BloggerBlogBundle_contact') }}" method="post" {{ form_enctype(form) }} class="blogger">
        {{ form_errors(form) }}

        {{ form_row(form.name) }}
        {{ form_row(form.email) }}
        {{ form_row(form.subject) }}
        {{ form_row(form.body) }}

        {{ form_rest(form) }}

        <input type="submit" value="Submit" />
    </form>
{% endblock %}

Style the form.###

Tạo file blog.css để định nghĩa style cho form.

//src/Blogger/BlogBundle/Resources/public/css/blog.css
.blogger-notice { text-align: center; padding: 10px; background: #DFF2BF; border: 1px solid; color: #4F8A10; margin-bottom: 10px; }
form.blogger { font-size: 16px; }
form.blogger div { clear: left; margin-bottom: 10px; }
form.blogger label { float: left; margin-right: 10px; text-align: right; awidth: 100px; font-weight: bold; vertical-align: top; padding-top: 10px; }
form.blogger input[type="text"],
form.blogger input[type="email"]
    { awidth: 500px; line-height: 26px; font-size: 20px; min-height: 26px; }
form.blogger textarea { awidth: 500px; height: 150px; line-height: 26px; font-size: 20px; }
form.blogger input[type="submit"] { margin-left: 110px; awidth: 508px; line-height: 26px; font-size: 20px; min-height: 26px; }
form.blogger ul li { color: #ff0000; margin-bottom: 5px; }

và import file css vừa tạo vào trong layout.

src/Blogger/BlogBundle/Resources/views/layout.html.twig

{% block stylesheets %}
    {{ parent() }}
    <link href="{{ asset('bundles/bloggerblog/css/blog.css') }}" type="text/css" rel="stylesheet" />
{% endblock %}

contact.jpg

###Validators### Symfony2 validator cho phép chúng ta làm việc với dữ liệu của form. Validation thực hiện kiểm tra dữ liệu trước khi được lưu vào cơ sở dữ liệu. CHúng ta sửa lại class Enquiry để chỉ định một số validators được sử dụng. Chú ý, 4 lệnh use ở đầu file.

<?php
// src/Blogger/BlogBundle/Entity/Enquiry.php

namespace BloggerBlogBundleEntity;
use SymfonyComponentValidatorMappingClassMetadata;
use SymfonyComponentValidatorConstraintsNotBlank;
use SymfonyComponentValidatorConstraintsEmail;
use SymfonyComponentValidatorConstraintsLength;

class Enquiry
{
    // ..

    public static function loadValidatorMetadata(ClassMetadata $metadata)
    {
        $metadata->addPropertyConstraint('name', new NotBlank());

        $metadata->addPropertyConstraint('email', new Email());

        $metadata->addPropertyConstraint('subject', new NotBlank());
        $metadata->addPropertyConstraint('subject', new Length(array('max' => 50)));

        $metadata->addPropertyConstraint('body', new Length(array('min' => 50)));
    }

    // ..
}

Nếu bạn muốn thay đổi thông báo lỗi mặc định. Bạn có thể thay đổi bằng cách sau: $$etadata->addPropertyConstraint('email', new Email(array( 'message' => 'symblog does not like invalid emails. Give me a real one!' )));

###Gửi email.### Hiện tại form cho phép người dùng submit tuy nhiên chưa xử lý gì bên trong. Bây giờ, chúng ta sẽ cập nhật lại controller để thực hiện việc gửi mail khi người dùng submit form.

Cấu hình Swift Mailer. Swift Mailer đã được cấu hình để làm việc với Symfony2. Tuy nhiên, chúng ta cần cấu hình lại một số thông tin cho chính xác ở app/config/parameters.yml

mailer_transport: gmail
mailer_encryption: ssl
mailer_auth_mode: login
mailer_host: smtp.gmail.com
mailer_user: your_username
mailer_password: your_password

Cập nhật Controlelr.

// src/Blogger/BlogBundle/Controller/PageController.php
public function contactAction()
{
    // ..
    if ($form->isValid()) {
                // Perform some action, such as sending an email
                $mailer = $this->get('mailer');
                $message = $mailer->createMessage()
                    ->setSubject('Contact enpuiry from symblog')
                    ->setFrom('anhtuan8591@gmail.com')
                    ->setTo('email@email.com')
                    ->setBody($this->renderView('BloggerBlogBundle:Page:contactEmail.txt.twig', array('enquiry' => $enquiry)));

                $mailer->send($message);

                //$this->get('session')->setFlash('blogger-notice', 'Your contact enquiry was successfully sent. Thank you!');

                // Redirect - This is important to prevent users re-posting
                // the form if they refresh the page
                return $this->redirect($this->generateUrl('BloggerBlogBundle_contact'));
            }
    // ..
}

###Tạo template cho email### Nội dung của email được render là 1 template. Bạn hãy tạo 1 file chứa template này.

{# src/Blogger/BlogBundle/Resources/views/Page/contactEmail.txt.twig #}
A contact enquiry was made by {{ enquiry.name }} at {{ "now" | date("Y-m-d H:i") }}.

Reply-To: {{ enquiry.email }}
Subject: {{ enquiry.subject }}
Body:
{{ enquiry.body }}

##Tổng kết## Bài viết này vừa trình bày cho các bạn nguyên lý đằng sau việc tạo một trong những phần cơ bản của bất kỳ website nào: forms. Symfony2 cung cấp thư việc Validator và Form cho phép bạn tách riêng logic validation of form để có thể sử dụng trong phần khác của ứng dụng (như là model). Bên cạnh đó, bài viết đã giới thiệu về thay đổi các cấu hình cho việc sử dụng mail cho ứng dụng.

Tham khảo Source code

0