형태
웹 개발자에게 HTML 양식 처리는 가장 일반적이고 어려운 작업 중 하나입니다. Symfony는 양식 구성 요소를 통합하여 양식 처리를 쉽게 만듭니다. 이 장에서는 복잡한 양식을 처음부터 작성하고 양식 라이브러리의 중요한 기능을 학습합니다.
Symfony의 Form 구성 요소는 Symfony 프로젝트 외부에서 사용할 수 있는 독립 클래스 라이브러리입니다. 자세한 내용은 Form 구성 요소 설명서를 참조하세요.
간단한 양식 만들기 ¶
일부 "작업"을 표시하기 위해 간단한 할 일 목록을 작성한다고 가정해 보겠습니다. 사용자가 작업을 편집하고 생성할 수 있도록 하려면 양식을 만들어야 합니다. 그 전에 단일 작업에 대한 데이터를 렌더링하고 저장할 수 있는 Task
클래스를 살펴보겠습니다. Task
类,它可呈现和存储一个单一任务的数据。
// src/AppBundle/Entity/Task.phpnamespace AppBundle\Entity; class Task{ protected $task; protected $dueDate; public function getTask() { return $this->task; } public function setTask($task) { $this->task = $task; } public function getDueDate() { return $this->dueDate; } public function setDueDate(\DateTime $dueDate = null) { $this->dueDate = $dueDate; }}
这是一个原生的PHP对象类,因为它没有和Symfony互动也没有引用其它类库。它是非常简单的一个PHP对象类,直接解决了 你 程序中的 task
(任务)之数据问题。当然,在本章的最后,你将能够通过HTML表单把数据提交到一个 Task
实例,验证它的值,并把它持久化到数据库。
构建表单 ¶
现在你已经创建了一个 Task
// src/AppBundle/Controller/DefaultController.phpnamespace AppBundle\Controller; use AppBundle\Entity\Task;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\Form\Extension\Core\Type\TextType;use Symfony\Component\Form\Extension\Core\Type\DateType;use Symfony\Component\Form\Extension\Core\Type\SubmitType; class DefaultController extends Controller{ public function newAction(Request $request) { // create a task and give it some dummy data for this example // 创建一个task对象,赋一些例程中的假数据给它 $task = new Task(); $task->setTask('Write a blog post'); $task->setDueDate(new \DateTime('tomorrow')); $form = $this->createFormBuilder($task) ->add('task', TextType::class) ->add('dueDate', DateType::class) ->add('save', SubmitType::class, array('label' => 'Create Task')) ->getForm(); return $this->render('default/new.html.twig', array( 'form' => $form->createView(), )); }}이것은 Symfony와 상호 작용하거나 다른 라이브러리를 참조하지 않기 때문에 기본 PHP 개체 클래스입니다. 귀하의 프로그램에서
task
(태스크)의 데이터 문제를 직접 해결하는 매우 간단한 PHP 객체 클래스입니다. 물론 이 장을 마치면 HTML 양식을 통해 Task
인스턴스에 데이터를 제출하고 해당 값의 유효성을 검사하고 데이터베이스에 유지할 수 있게 됩니다. 양식 작성 ¶
작업
이 생성되었습니다. 클래스의 다음 단계는 실제 HTML 양식을 만들고 렌더링하는 것입니다. Symfony에서는 양식 객체를 구축하고 이를 템플릿에 렌더링하여 이를 수행합니다. 이제 컨트롤러에서 모든 작업을 수행할 수 있습니다. TWIG:{# app/Resources/views/default/new.html.twig #} {{ form_start(form) }} {{ form_widget(form) }} {{ form_end(form) }}
Symfony의 양식 개체는 "양식 작성기"를 통해 생성되므로 양식을 만드는 데 많은 코드가 필요하지 않습니다. 폼 빌더의 목적은 간단한 폼 생성 "지침"을 작성할 수 있도록 하는 것이며, 실제로 폼을 생성할 때 모든 "오버로딩" 작업은 빌더에 의해 완료됩니다.
이 예에서는 양식에 task
및 dueDate
라는 두 개의 필드를 추가했습니다. Task
클래스의 task
및 dueDate
속성에 해당합니다. FQCN(전체 정규 클래스 이름/전체 경로 클래스 이름)의 "유형"을 각각 지정했습니다(예: TextType
, DateType
). 필드에 대해 생성할 HTML 양식 태그(태그 그룹)를 입력합니다. task
和 dueDate
。对应的是 Task
类中的 task
和 dueDate
属性。你已为它们分别指定了FQCN(Full Quilified Class Name/完整路径类名)的“类型”(如 TextType
, DateType
),由类型决定为字段生成哪一种HTML表单标签(标签组)。
最后,你添加了一个带有自定义label的提交按钮以向服务器提交表单。
Symfony附带了许多内置类型,它们将被简短地介绍(见下面的内置表单类型)。
渲染表单 ¶
表单创建之后,下一步就是渲染它。这是通过传递一个特定的表单“view”对象(注意上例控制器中的 $form->createView()
方法)到你的模板,并通过一系列的表单helper function(帮助函数)来实现的。
PHP:<!-- app/Resources/views/default/new.html.php --> <?php echo $view['form']->start($form) ?> <?php echo $view['form']->widget($form) ?> <?php echo $view['form']->end($form) ?>
// ...use Symfony\Component\HttpFoundation\Request; public function newAction(Request $request){ // just setup a fresh $task object (remove the dummy data) // 直接设置一个全新$task对象(删除了假数据) $task = new Task(); $form = $this->createFormBuilder($task) ->add('task', TextType::class) ->add('dueDate', DateType::class) ->add('save', SubmitType::class, array('label' => 'Create Task')) ->getForm(); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { // $form->getData() holds the submitted values // but, the original `$task` variable has also been updated // $form->getData() 持有提交过来的值 // 但是,原始的 `$task` 变量也已被更新了 $task = $form->getData(); // ... perform some action, such as saving the task to the database // for example, if Task is a Doctrine entity, save it! // 一些操作,比如把任务存到数据库中 // 例如,如果Tast对象是一个Doctrine entity,存下它! // $em = $this->getDoctrine()->getManager(); // $em->persist($task); // $em->flush(); return $this->redirectToRoute('task_success'); } return $this->render('default/new.html.twig', array( 'form' => $form->createView(), ));}
本例假设你以"POST"请求提交表单,并且提交到和“表单显示(页面)”相同的URL。后面你将学习如何改变请求方法(request method)和表单提交后的目标URL。
就是这样!只需要三行就可以渲染出完整的form表单:
form_start(form)
- 渲染表单的开始标签,包括在使用文件上传时的正确enctype属性。
form_widget(form)
- 渲染出全部字段,包含字段元素本身,字段label以及字段验证的任何错误信息。
form_end(form)
마지막으로 사용자 정의 라벨이 있는 제출 버튼을 추가하여 양식을 서버에 제출합니다. - Symfony에는 다양한 기본 제공 유형이 제공되며 이에 대해 간단히 소개하겠습니다(아래 내장 양식 유형 참조).
양식 렌더링 ¶
양식이 생성된 후 다음 단계 렌더링하는 것입니다. 이는 특정 양식 "보기" 객체(위 예제 컨트롤러의
$form->createView()
메서드 참고)를 템플릿에 전달하고 일련의 양식 도우미 함수( 도우미 기능)을 달성합니다. Annotations:// src/AppBundle/Entity/Task.phpnamespace AppBundle\Entity; use Symfony\Component\Validator\Constraints as Assert; class Task{ /** * @Assert\NotBlank() */ public $task; /** * @Assert\NotBlank() * @Assert\Type("\DateTime") */ protected $dueDate;}
YAML:# src/AppBundle/Resources/config/validation.ymlAppBundle\Entity\Task: properties: task: - NotBlank: ~ dueDate: - NotBlank: ~ - Type: \DateTime
- #🎜🎜#
form_start(form)
#🎜🎜## 🎜🎜 #파일 업로드를 사용할 때 올바른 enctype 속성을 포함하여 양식의 시작 태그를 렌더링합니다. #🎜🎜##🎜🎜#form_widget(form)
#🎜🎜##🎜🎜#필드 요소 자체, 필드 레이블 및 필드 유효성 검사 오류를 포함한 모든 필드를 렌더링합니다. 정보. #🎜🎜##🎜🎜#form_end(form)
#🎜🎜##🎜🎜#각 필드를 수동으로 생성하면 양식 종료 태그와 양식 끝 태그를 렌더링할 수 있습니다. form 아직 렌더링되지 않은 모든 필드입니다. 이는 숨겨진 필드를 렌더링하고 자동 기능을 활용할 때 유용합니다.
#🎜🎜##🎜🎜#CSRF Protection#🎜🎜##🎜🎜#은 메커니즘을 보호할 때 매우 유용합니다. #🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜# 그렇게 간단하지만 그다지 유연하지는 않습니다(현재로서는). 일반적으로 양식의 스타일을 제어하기 위해 양식의 각 필드를 개별적으로 렌더링하려고 합니다. 다음 기사 #🎜🎜#양식 렌더링 제어 방법#🎜🎜#에서 이 방법을 익히게 됩니다. #🎜🎜##🎜🎜##🎜🎜#계속하기 전에 렌더링된 task
입력 상자에 $task
개체의 속성 값이 있는 이유를 확인하세요(예: "블로그 게시물 작성" "). 이것이 양식의 첫 번째 작업입니다. 즉, 개체에서 데이터를 가져와 HTML 양식으로 렌더링할 수 있도록 적절한 형식으로 변환하는 것입니다. task
输入框中有一个来自 $task
对象的属性值(即“Write a blog post”)。这是表单的第一个任务:从一个对象中获取数据并把它转换成一种适当的格式,以便在HTML表单中被渲染。
表单系统足够智能,它们通过 getTask()
和 setTask()
方法来访问 Task
类中受保护的 task
属性。除非是public属性,否则 必须 有一个 "getter" 和 "setter" 方法被定义,以便表单组件能从这些属性中获取和写入数据。对于布尔型的属性,你可以使用一个 "isser" 和 "hasser" 方法(如 isPublished()
和 hasReminder()
)来替代getter方法(getPublished()
和 getReminder()
)。
处理表单提交 ¶
默认时,表单会把POST请求,向“渲染它的同一个控制器”提交回去。
此处,表单的第二个任务就是把用户提交的数据传回到一个对象的属性之中。要做到这一点,用户提交的数据必须写入表单对象才行。向控制器(Controller)中添加以下功能:
XML:<!-- src/AppBundle/Resources/config/validation.xml --><?xml version="1.0" encoding="UTF-8"?><constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> <class name="AppBundle\Entity\Task"> <property name="task"> <constraint name="NotBlank" /> </property> <property name="dueDate"> <constraint name="NotBlank" /> <constraint name="Type">\DateTime</constraint> </property> </class></constraint-mapping>
注意 createView()
方法应该在 handleRequest
被调用 之后 再调用。否则,针对 *_SUBMIT
getTask()를 전달합니다. code> 및 setTask()
메서드를 사용하여 Task
클래스의 보호된 task
속성에 액세스합니다. 공용 속성이 아닌 이상, 양식 구성 요소가 이러한 속성에서 데이터를 가져오고 쓸 수 있도록 "getter" 및 "setter" 메서드가 정의되어 반드시 있습니다. 부울 속성의 경우 getter 메서드() 대신 "isser" 및 "hasser" 메서드(예: isPublished()
및 hasReminder()
)를 사용할 수 있습니다. getPublished()
및 getReminder()
).
양식 제출 처리 ¶
#🎜🎜# 기본적으로 양식은 POST 요청을 "렌더링한 동일한 컨트롤러"에 다시 제출합니다. #🎜🎜##🎜🎜#여기서 양식의 두 번째 작업은 사용자가 제출한 데이터를 개체의 속성으로 다시 전송하는 것입니다. 이렇게 하려면 사용자가 제출한 데이터를 양식 개체에 기록해야 합니다. 컨트롤러에 다음 기능을 추가합니다: #🎜🎜#PHP:// src/AppBundle/Entity/Task.phpuse Symfony\Component\Validator\Mapping\ClassMetadata;use Symfony\Component\Validator\Constraints\NotBlank;use Symfony\Component\Validator\Constraints\Type; class Task{ // ... public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('task', new NotBlank()); $metadata->addPropertyConstraint('dueDate', new NotBlank()); $metadata->addPropertyConstraint( 'dueDate', new Type('\DateTime') ); }}#🎜🎜##🎜🎜#
createView()
메서드는 다음과 같습니다. handleRequest
가 호출된 후에 호출됩니다. 그렇지 않으면 *_SUBMIT
양식 이벤트에 대한 수정 사항이 뷰 레이어에 적용되지 않습니다(예: 유효성 검사 중 오류 메시지). #🎜🎜##🎜🎜#컨트롤러는 양식을 처리할 때 일반적인 패턴을 따릅니다.
#🎜🎜 #- When 브라우저가 처음에 페이지를 로드하면 양식이 생성되고 렌더링됩니다.
handleRequest()
는 양식이 제출되지 않았음을 인식하고 아무 작업도 수행하지 않습니다. 양식이 제출되지 않은 경우isSubmitted()
는 false를 반환합니다. 当用户提交表单时,
handleRequest()
会识别这个动作并立即将提交的数据写入到$task
对象的task
anddueDate
属性。然后该对象被验证。如果它是无效的(验证在下一章),isValid()
会返回false
,进而表单被再次渲染,只是这次有验证错误;当用户以合法数据提交表单的时,提交的数据会被再次写入到表单,但这一次
사용자가 양식을 제출하면isValid()
返回true
。在把用户重定向到其他一些页面之前(如一个“谢谢”或“成功”的页面),你有机会用$task
handlerRequest()
는 이 작업을 인식하고 제출된 데이터를$task
task<에 즉시 씁니다. > 개체 /code> 및dueDate
속성. 그런 다음 개체의 유효성이 검사됩니다. 유효하지 않은 경우(확인은 다음 장에서 확인)isValid()
는false
를 반환하고 양식이 렌더링됩니다. 그런데 이번에는 유효성 검사 오류가 발생했습니다;#🎜🎜#양식이 성공적으로 제출된 후 사용자를 리디렉션하는 것은 사용자가 브라우저 "새로 고침" 버튼을 통해 반복적으로 데이터를 제출하는 것을 방지하기 위한 것입니다. #🎜🎜##🎜🎜##🎜🎜#사용자가 법적 데이터가 포함된 양식을 제출하면 제출된 데이터가 다시 양식에 기록되지만 이는 시간
isValid()
는true
를 반환합니다. 사용자를 다른 페이지(예: "감사합니다" 또는 "성공" 페이지)로 리디렉션하기 전에$task
개체를 사용하여 일부 작업을 수행할 수 있습니다( 예를 들어 데이터베이스에 유지합니다.
handleRequest()
意识到表单没有被提交进而什么都不做。如果表单未被提交,isSubmitted()
返回false;양식이 제출되는 시기나 양식에 전달되는 데이터를 정확하게 제어해야 하는 경우 submit( ) . 자세한 내용은 수동으로 양식 호출::submit()을 참조하세요.
양식 유효성 검사 ¶
이전 섹션에서 유효하거나 유효하지 않은 데이터가 How와 함께 제공된다는 것을 배웠습니다. 양식이 제출되었습니다. Symfony에서 확인 프로세스는 기본 개체(예: Task
)에서 수행됩니다. 즉, 문제는 "양식"이 유효한지 여부가 아니라 "제출된 데이터가 양식에 적용"된 후 $task
개체가 유효한지 여부입니다. $form->isvalid()
를 호출하는 것은 기본 $task
개체가 유효한 데이터를 얻었는지 묻는 간단한 방법입니다. Task
)。换句话说,问题不在于“表单”是否有效,而是 $task
对象在“提交的数据应用到表单”之后是否合法。调用 $form->isvalid()
是一个快捷方式,询问底层 $task
对象是否获得了合法数据。
验证(validation)是通过把一组规则(称之为“constraints/约束”)添加到一个类中来完成的。我们给 Task
类添加规则和约束,使task属性不能为空, duDate
字段不空且必须是一个有效的DateTime对象。
PHP:<!-- app/Resources/views/default/new.html.php --><?php echo $view['form']->form($form, array( 'attr' => array('novalidate' => 'novalidate'),)) ?>
Twig:{# app/Resources/views/default/new.html.twig #} {{ form(form, {'attr': {'novalidate': 'novalidate'}}) }}
1
->add('dueDate', DateType::class, array('widget' => 'single_text'))
就是这样!如果你现在重新以非法数据提交表单,你将会看到相应的错误被输出到表单。
验证是Symfony一个非常强大的功能,它拥有自己的专属章节。
각 필드 유형에는 유형을 전달하기 위한 다양한 옵션 세트가 있습니다. 필드 유형에 대한 자세한 내용은 각 유형에 대한 설명서에서 확인할 수 있습니다.
字段类型猜测 ¶
现在你已经添加了验证元数据(译注:即annotation)到 Task
类,Symfony对于你的字段已有所了解。如果你允许,Symfony可以“猜到”你的字段类型并帮你设置好。在下面的例子中,Symfony可以根据验证规则猜测到 task
字段是一个标准的 TextType
字段, dueDate
是 DateType
字段。
1
当你省略了 add()
方法的第二个参数(或者你输入 null
)时,“猜测”会被激活。如果你输入一个选项数组作为第三个参数(比如上面的 dueDate
$form->get('dueDate')->getData();
required
를 true
로 설정하고 을 NotBlank를 사용하지 않는 한 빈 값은 유효한 값으로 허용됩니다.
또는 NotNull
유효성 검사 제약 조건. 즉, 필수
옵션은 "좋지만" 서버측 유효성 검사는 항상
레이블을 사용할 수 있습니다.
옵션을 사용하면 모든 필드에 적용되는 양식 필드의 레이블을 설정할 수 있습니다. #🎜🎜#1#🎜🎜#필드의 레이블은 템플릿이 양식을 렌더링할 때 설정할 수도 있습니다. 아래를 참조하세요. 입력에 레이블을 연결할 필요가 없으면 옵션 값을
false
로 설정할 수 있습니다. #🎜🎜##🎜🎜##🎜🎜##🎜🎜#필드 유형 추측 ¶
#🎜🎜#이제Task
클래스에 유효성 검사 메타데이터(주석)를 추가했으므로 Symfony는 이미 필드에 대해 알고 있습니다. 허용하면 Symfony가 필드 유형을 "추측"하여 설정할 수 있습니다. 다음 예에서 Symfony는 task
필드가 표준 TextType
필드이고 dueDate
가 라는 유효성 검사 규칙을 기반으로 추측할 수 있습니다. >날짜 유형< /code> 필드. #🎜🎜#$form->get('dueDate')->setData(new \DateTime());
#🎜🎜#add()
메서드의 두 번째 매개변수를 생략하거나 null
을 입력하면 "Guess"가 활성화됩니다. 옵션 배열을 세 번째 인수(예: 위의 dueDate
)로 입력하면 이러한 옵션이 추측된 필드에 적용됩니다. #🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#양식에서 특정 유효성 검사 그룹을 사용하는 경우 필드 유형을 추측하면 #🎜🎜#all#🎜 🎜# 유효성 검사 제약 조건(제약 조건 포함)이 고려됩니다. 이 "사용 중" 검증 그룹에 속하지 않는 것). #🎜🎜##🎜🎜##🎜🎜#필드 유형에 대한 옵션 추측 ¶
Symfony는 필드 유형을 추측하는 것 외에도 필드 옵션에 대한 올바른 값을 추측하려고 시도할 수도 있습니다.
이러한 옵션을 설정하면 HTML5의 클라이언트 측 유효성 검사를 위해 특수 HTML 속성을 사용하여 필드가 렌더링됩니다. 그러나 서버 측에서는 해당 유효성 검사 규칙(예: AssertLength
)을 생성하지 않습니다. 이러한 서버측 규칙을 수동으로 추가해야 하지만 이러한 규칙을 기반으로 이러한 필드 유형에 대한 옵션을 추측할 수 있습니다. AssertLength
)。尽管你需要手动地添加这些服务器端的规则,这些字段类型的选项接下来可以根据这些规则被猜出来。
required
required
选项可以基于验证规则 (如,该字段是否为 NotBlank
或 NotNull
) 或者是Doctrine的metadata元数据 (如,该字段是否为 nullable
) 而被猜出来。这非常有用,因为你的客户端验证将自动匹配到你的验证规则。max_length
- 如果字段是某些列文本型字段,那么
max_length
选项可以基于验证约束 (字段是否应用了 Length
或 Range
) 或者是Doctrine元数据 (通过该字段的长度) 而被猜出来。
这些字段选项 仅 在你使用Symfony进行类型猜测时(即,忽略参数,或传入null
作为 add()
필수
필수
옵션은 다음과 같습니다. 유효성 검사 규칙(예: 필드가 NotBlank
또는 NotNull
인지 여부) 또는 Doctrine 메타데이터(예: 필드가 nullable
로 추측됩니다). 클라이언트 측 유효성 검사가 자동으로 유효성 검사 규칙과 일치하므로 이는 매우 유용합니다. max_length
- 필드가 일부 열 텍스트 필드인 경우
max_length
옵션은 유효성 검사 제약 조건(필드에 길이
또는 범위
가 적용되었는지 여부) 또는 Doctrine 메타데이터( 필드) 추측할 수 있습니다.
이러한 필드 옵션은 유형 추측을 위해 Symfony를 사용할 때만 사용할 수 있습니다(예: 인수 무시 또는 전달). add()
메서드의 두 번째 매개변수인 < code>null)이 추측됩니다.
추측된(옵션) 값을 변경하려면 필드 유형의 옵션 배열에 이 항목을 전달하여 재정의할 수 있습니다. rrreee rrreee
🎜🎜🎜🎜폼 클래스 생성 ¶
보시다시피 컨트롤러에서 직접 폼을 생성하고 사용할 수 있습니다. 그러나 더 나은 접근 방식은 별도의 PHP 클래스에서 양식을 만드는 것입니다. 프로그램의 어느 곳에서나 재사용할 수 있습니다. "작업 양식 작성"에 필요한 논리를 보유하는 새 클래스를 만듭니다.
rrreee이 새 클래스에는 작업 양식을 만드는 데 필요한 모든 측면이 포함되어 있습니다. 컨트롤러에서 양식을 빠르게 생성하는 데 사용할 수 있습니다.
rrreee양식 로직을 자체 클래스에 넣으면 프로젝트의 어느 곳에서나 양식을 쉽게 재사용할 수 있습니다. 이것이 양식을 작성하는 가장 좋은 방법이지만 결정은 귀하에게 달려 있습니다.
当把表单映射成对象时,所有的字段都将被映射。表单中的任何字段如果在映射对象上“不存在”,都会抛出异常。
当你需要在表单中使用附加字段(如,一个 “你是否同意这些声明?”的复选框)而这个字段将不被映射到底层对象时,你需要设置 mapped
选项为 false
:
rrreee另外,若表单的任何字段未包含在提交过来的数据中,那么这些字段将被显式设置为 null
rrreee
양식을 개체에 매핑하면 모든 필드가 매핑됩니다. 매핑된 개체에 "존재하지 않는" 형식의 모든 필드는 예외를 발생시킵니다. 양식에서 추가 필드를 사용해야 하고(예: "이 설명에 동의하십니까?" 확인란) 이 필드가 기본 개체에 매핑되지 않는 경우 다음을 설정해야 합니다. < 코드>매핑 옵션이 false
입니다: rrreee또한 양식의 필드가 제출된 데이터에 포함되지 않은 경우 해당 필드는 명시적으로 null
로 설정하세요. 컨트롤러에서 필드 데이터(필드 값)에 액세스할 수 있습니다. #🎜 🎜# rrreee
rrreee #🎜 🎜# 또한 매핑되지 않은 필드의 데이터를 직접 수정할 수도 있습니다. # 🎜🎜# rrreee
rrreee#🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#최종 생각 ¶
양식을 작성할 때 기본 목표는 객체(task
)의 데이터를 HTML 형식으로 변환하여 사용자가 (양식) 값을 수정할 수 있도록 하는 것입니다. 두 번째 목표는 사용자가 제출한 데이터를 가져와 해당 개체에 대해 다시 작업을 수행하는 것입니다.
아직 마스터해야 할 부분이 많고 양식 시스템에는 powerful 고급 기술이 많이 있습니다.