HTML 양식을 만들 때 반복적이고 다른 프로젝트에서 재사용하기 어려운 뷰 코드를 많이 작성하는 경우가 많습니다. 예를 들어 각 입력 필드에 대해 이를 텍스트 레이블과 연결하고 가능한 유효성 검사 오류를 표시해야 합니다. 이 코드의 재사용성을 향상시키기 위해 버전 1.1.0부터 사용 가능한 양식 작성 기능을 사용할 수 있습니다.
Yii 양식 생성기는 CForm 개체를 사용하여 HTML 양식을 설명하는 데 필요한 콘텐츠(이 양식과 연결된 데이터 모델, 양식에 포함된 입력 상자 포함)를 나타냅니다. , 그리고 전체 양식을 렌더링하는 방법. 개발자는 주로 이 CForm 개체를 만들고 구성한 다음 렌더링 메서드를 호출하여 양식을 표시해야 합니다.
양식의 입력 상자 매개변수는 양식 요소를 기반으로 계층 구조로 구성됩니다. 구조의 최상위 수준에는 CForm 개체가 있습니다. 이 개체의 멤버는 CForm::buttons 및 CForm::elements라는 두 가지 범주로 나뉩니다. 전자에는 버튼 요소(예: 제출 버튼, 재설정 버튼)가 포함되고 후자에는 입력 요소, 정적 텍스트 및 하위 양식이 포함됩니다. 하위 폼도 CForm 개체이지만 다른 폼의 CForm::elements에 존재합니다. 하위 양식에는 자체 데이터 모델인 CForm::buttons 및 CForm::elements 컬렉션이 있을 수 있습니다.
사용자가 양식을 제출하면 하위 양식에 채워진 데이터를 포함하여 전체 양식 구조에 채워진 데이터가 제출됩니다. CForm은 입력 데이터를 해당 데이터 속성에 자동으로 할당하고 데이터 유효성 검사를 수행할 수 있는 편리한 메서드를 제공합니다.
아래에서는 양식 빌더를 사용하여 로그인 양식을 만드는 방법을 보여줍니다.
먼저 로그인 작업 코드를 작성합니다.
public function actionLogin() { $model = new LoginForm; $form = new CForm('application.views.site.loginForm', $model); if($form->submitted('login') && $form->validate()) $this->redirect(array('site/index')); else $this->render('login', array('form'=>$form)); }
위 코드에서는 다음을 사용합니다. CForm 개체는 경로 별칭 application.views.site.loginForm
(간단히 설명함)에 지정된 매개 변수를 사용하여 생성됩니다. CForm 개체는 LoginForm
모델(모델 만들기에서 소개됨)과 연결됩니다.
코드에 표시된 대로 양식이 제출되고 모든 입력이 오류 없이 검증되면 사용자의 브라우저가 site/index
페이지로 리디렉션됩니다. 그렇지 않으면 이 양식을 사용하여 login
뷰를 렌더링합니다.
경로 별칭 application.views.site.loginForm
은 실제로 PHP 파일 protected/views/site/loginForm.php
을 나타냅니다. 이 파일은 다음과 같이 CForm에 필요한 구성을 나타내는 PHP 배열을 반환해야 합니다.
return array( 'title'=>'Please provide your login credential', 'elements'=>array( 'username'=>array( 'type'=>'text', 'maxlength'=>32, ), 'password'=>array( 'type'=>'password', 'maxlength'=>32, ), 'rememberMe'=>array( 'type'=>'checkbox', ) ), 'buttons'=>array( 'login'=>array( 'type'=>'submit', 'label'=>'Login', ), ), );
구성은 CForm의 해당 속성을 초기화하는 데 사용되는 키-값 쌍으로 구성된 연관 배열입니다. 앞에서 언급했듯이 구성해야 할 가장 중요한 속성은 CForm::elements 및 CForm::buttons입니다. 각각은 양식 요소 목록을 지정하는 배열입니다. 다음 섹션에서는 양식 요소를 구성하는 방법에 대해 자세히 설명합니다.
마지막으로 이렇게 간결하게 login
뷰를 작성합니다.
<h1>Login</h1> <p class="form"> <?php echo $form; ?> </p>
팁: 위 코드
echo $form;
는echo $form->render();
과 동일합니다. 이는 CForm이__toString
를 호출하고 해당 결과를 이 양식 개체를 나타내는 문자열로 반환하는render()
매직 메서드를 구현하기 때문입니다.
양식 작성기를 사용하면 대부분의 작업이 보기 스크립트 코드 작성에서 양식 요소 지정으로 전환됩니다. 이 섹션에서는 CForm::elements 특성을 지정하는 방법을 설명합니다. CForm::buttons의 구성은 CForm::elements의 구성과 거의 동일하므로 다루지 않습니다.
CForm::elements 속성은 배열을 값으로 허용합니다. 각 배열 요소는 입력 상자, 정적 텍스트 문자열 또는 하위 양식일 수 있는 별도의 양식 요소를 지정합니다.
입력 요소 지정
입력 요소는 크게 라벨, 입력 상자, 프롬프트 텍스트, 오류 표시로 구성됩니다. 모델 속성과 연결되어야 합니다. 입력 요소의 사양은 CFormInputElement 인스턴스로 표시됩니다. CForm::elements 배열의 다음 코드는 단일 입력 요소를 지정합니다.
'username'=>array( 'type'=>'text', 'maxlength'=>32, ),
모델 특성을 나타냅니다. 이름은 username
이고 입력 상자 유형은 text
이며 maxlength
속성은 32입니다.
任何 CFormInputElement 可写的属性都可以如上配置。例如,我们可以指定 hint 选项来显示提示信息,或者我们可以指定 items 选项若输入框是一个 list box,一个下拉列表,一个多选列表或一个单选按钮列表。 若选项的名字不是一个CFormInputElement 属性,它将被认为是对应 HTML 输入元素的属性, 例如,因为上面的 maxlength
不是一个CFormInputElement 属性,它被渲染作为 HTML 文本输入框的 maxlength
属性。
type 选项需要特别注意。它指定了输入框的类型。 例如,text
类型意味着将渲染一个普通的文本输入框;password
类型意味着将渲染一个密码输入框。 CFormInputElement 识别如下内置的类型:
text
hidden
password
textarea
file
radio
checkbox
listbox
dropdownlist
checkboxlist
radiolist
在上面的内置类型中,我们想要对这些 "list" 类型的用法多说一些, 包括 dropdownlist
, checkboxlist
和radiolist
。这些类型需要设置对应输入元素的 items 属性。可以这样做:
'gender'=>array( 'type'=>'dropdownlist', 'items'=>User::model()->getGenderOptions(), 'prompt'=>'Please select:', ), ... class User extends CActiveRecord { public function getGenderOptions() { return array( 0 => 'Male', 1 => 'Female', ); } }
上面的代码将生成一个下拉列表选择器,提示文字是 “please select:”。选项包括 “Male” 和 “Female”,它们是由 User
模型类中的 getGenderOptions
方法返回的。
除了这些内置的类型, type 选项也可以是一个 widget 类名字或 widget 类的路径别名。 widget 类必须扩展自CInputWidget 或 CJuiInputWidget。当渲染输入元素时, 一个指定 widget 类的实例将被创建并渲染。The widget will be configured using the specification as given for the input element.
指定静态文本
很多情况下,一个表单包含一些装饰性的 HTML 代码。 例如,一个水平线被用来分隔表单中不同的部分;一个图像出现在特定的位置来增强表单的视觉外观。 我们可以在 CForm::elements 集合中指定这些 HTML 代码作为静态文本。要这样做,我们只要指定一个静态文本字符串作为一个数组元素,在 CForm::elements 恰当的位置。例如,
return array( 'elements'=>array( ...... 'password'=>array( 'type'=>'password', 'maxlength'=>32, ), '<hr />', 'rememberMe'=>array( 'type'=>'checkbox', ) ), ...... );
在上面,我们在 password
输入框和 rememberMe
之间插入一个水平线。
静态文本最好用于文本内容和它们的位置不规则时。 若表单中的每个输入元素需要被相似的装饰,我们应当定制表单渲染方法,此章节将简短介绍。
指定子表单
子表单被用来分离一个长的表单为几个逻辑部分。 例如,我们可以分离用户注册表单为两部分:登录信息和档案信息。 每个子表单和一个数据模型有无关联均可。例如在用户注册表单,若我们存储用户登录信息和档案信息到两个分离的数据表中(表示为两个数据模型), 然后每个子表单需要和一个对应的数据模型关联。若我们存储所有信息到一个数据表中,任意一个子表单都没有数据模型,因为它们和根表单分享相同的模型。
一个子表单也表示为一个CForm 对象。要指定一个子表单,我们应当配置 CForm::elements 属性为一个类型是 form
的元素:
return array( 'elements'=>array( ...... 'user'=>array( 'type'=>'form', 'title'=>'Login Credential', 'elements'=>array( 'username'=>array( 'type'=>'text', ), 'password'=>array( 'type'=>'password', ), 'email'=>array( 'type'=>'text', ), ), ), 'profile'=>array( 'type'=>'form', ...... ), ...... ), ...... );
类似于配置一个根表单,我们主要需要为一个子表单指定 CForm::elements 属性。若一个子表单需要关联一个数据模型,我们也可以配置它的 CForm::model 属性。
有时,我们想要使用一个类代表表单,而不使用默认的 CForm 类。例如, 此小节将简短展示,我们可以扩展 CForm以定制表单渲染逻辑。 通过指定输入元素的类型为 form
,一个子表单将自动被表示为一个对象,它的类和它的父表单相同。若我们指定输入元素的类型类似于 XyzForm
(一个以 Form
结尾的字符串), 然后子表单将被表示为一个XyzForm
对象。
访问表单元素和访问数组元素一样简单。CForm::elements 属性返回一个 CFormElementCollection 对象, 它扩展自 CMap 并允许以类似于一个普通数组的方式来访问它的元素。例如,要访问登录表单中的元素 username
,我们可以使用下面的代码:
$username = $form->elements['username'];
要访问用户注册表单中的 email
元素,使用
$email = $form->elements['user']->elements['email'];
因为 CForm 为它的 CForm::elements 属性执行数组访问,上面的代码可以简化为:
$username = $form['username']; $email = $form['user']['email'];
我们已经描述了子表单。我们称一个有子表单的表单为一个嵌套表单。在这一章节, 我们使用用户注册表单作为例子来展示如何创建一个关联多个数据模型的嵌套表单。我们假设用户的认证信息存储为一个 User
模型,而用户的档案信息被存储为一个 Profile
模型。
我们首先创建 register
action 如下:
public function actionRegister() { $form = new CForm('application.views.user.registerForm'); $form['user']->model = new User; $form['profile']->model = new Profile; if($form->submitted('register') && $form->validate()) { $user = $form['user']->model; $profile = $form['profile']->model; if($user->save(false)) { $profile->userID = $user->id; $profile->save(false); $this->redirect(array('site/index')); } } $this->render('register', array('form'=>$form)); }
在上面,我们使用由 application.views.user.registerForm
指定的配置创建了表单。 在表单被提交且成功验证之后,我们尝试保存 user 和 profile 模型。 我们通过访问相应子表单对象的 model
属性来检索 user 和 profile 模型。 因为输入验证已经完成,我们调用 $user->save(false)
来跳过验证。为 profile 模型也这样做。
接下来,我们编写表单配置文件 protected/views/user/registerForm.php
:
return array( 'elements'=>array( 'user'=>array( 'type'=>'form', 'title'=>'Login information', 'elements'=>array( 'username'=>array( 'type'=>'text', ), 'password'=>array( 'type'=>'password', ), 'email'=>array( 'type'=>'text', ) ), ), 'profile'=>array( 'type'=>'form', 'title'=>'Profile information', 'elements'=>array( 'firstName'=>array( 'type'=>'text', ), 'lastName'=>array( 'type'=>'text', ), ), ), ), 'buttons'=>array( 'register'=>array( 'type'=>'submit', 'label'=>'Register', ), ), );
在上面,当指定每个子表单时,我们也指定它的 CForm::title 属性。 默认的表单渲染逻辑将封装每个子表单到一个 field-set 中,使用此属性作为它的标题。
最后,我们编写 register
视图脚本:
<h1>Register</h1> <p class="form"> <?php echo $form; ?> </p>
使用表单生成器最主要的好处是逻辑 (表单配置被存储在一个单独的文件中) 和表现 (CForm::render方法) 的分离。 这样,我们可以实现定制表单显示,通过重写 CForm::render 或提供一个局部视图来渲染表单。两种方法都可以保持表单配置的完整性,并且可以容易地重用。
当重写 CForm::render 时, 你主要需要遍历 CForm::elements 和 CForm::buttons 并调用每个表单元素的CFormElement::render 方法。例如,
class MyForm extends CForm { public function render() { $output = $this->renderBegin(); foreach($this->getElements() as $element) $output .= $element->render(); $output .= $this->renderEnd(); return $output; } }
可能我们也需要写一个视图脚本 _form
以渲染一个视图:
<?php echo $form->renderBegin(); foreach($form->getElements() as $element) echo $element->render(); echo $form->renderEnd();
要使用此视图脚本,我们需要调用:
<p class="form"> $this->renderPartial('_form', array('form'=>$form)); </p>
若一个通用的表单渲染不适用于一个特殊的表单(例如,表单为特定的元素需要不规则的装饰),在视图脚本中我们可以这样做:
some complex UI elements here <?php echo $form['username']; ?> some complex UI elements here <?php echo $form['password']; ?> some complex UI elements here
在最后的方法中,表单生成器看起来并没有带来好处,因为我们仍然需要写很多表单代码。然而,它仍然是有好处的,表单被使用一个分离的配置文件指定,这样可以帮助开发者更专注于逻辑部分。
以上就是Yii框架官方指南系列21——使用表单:使用表单生成器(CForm)的内容,更多相关内容请关注PHP中文网(www.php.cn)!