我正在开发一个涉及在高级抽象中生成表单的应用程序(它是一个CMS应用程序)。我想动态创建CFormModel对象并动态设置表单字段。我想我可以通过扩展CFormModel,然后动态创建代表表单字段的类属性(Yii术语中的“属性”)来做到这一点。
为了说明,不是在下面的类中指定登录表单(在文件中定义):
// From: http://www.yiiframework.com/doc/guide/1.1/en/form.model
class LoginForm extends CFormModel
{
public $username;
public $password;
public $rememberMe=false;
private $_identity;
public function rules()
{
return array(
array('username, password', 'required'),
array('rememberMe', 'boolean'),
array('password', 'authenticate'), // assume function authenticate defined elsewhere
);
}
}
我想这样做:
class MyFormModel extends CFormModel {
protected $_rules = array();
public function __construct($attributes=array(), $rules=array()) {
foreach ($attributes as $i => $attr) {
$this->{$attr} = ???; // <<== This is the key here
}
// pass in array of rules as described in Yii doc for CFormModel
$this->_rules = $rules;
}
public function rules() {
return $_rules;
}
}
并在需要时调用它,如下所示:
$myModelObj = new MyFormModel($attr, $rules);
其中:
$attr = array(
'username',
'rememberMe',
'password',
);
$rules = array(
array('username, password', 'required'),
array('rememberMe', 'boolean'),
array('password', 'authenticate'), // assume function authenticate defined elsewhere
);
请注意,在我要完成的任务中,没有任何文件中写入“LoginClass”,它是在代码中即时创建的。
这可以让我创建表单(在视图中)做这样的事情:
// based on http://www.yiiframework.com/doc/guide/1.1/en/form.view
<?php echo $wForm->textField($myModelObj,'username'); ?>
等
我已经尝试过了,$ this-&gt; {$ attr}行失败了:
Property "MyFormModel.username" is not defined.
实际上该行的代码只是:
$this->{$attr};
???表示我不确定要分配给它的内容。在Yii doc示例中,它们只是将字段定义为公共类变量。
我应该使用魔术方法吗?
我想在这里做什么甚至可能?
答案 0 :(得分:4)
您可能知道Yii使用OOP overloading来解析类似AR的属性。
这里你需要做的事情与Yii内部做的类似。
定义硬编码属性以存储所有自定义属性,如数组:$_data
这个数据将是一个数组,它将包含您在运行时添加的所有属性。您可能需要通过覆盖魔术方法(setter,getters,isset)来挑战验证,如Yii所做,首先从您的$_data
财产持有者处解析属性名称。
您在CActiveRecord中找到的某种代码会查找所有__XXX
类似的方法。
如果您将AR属性处理复制到自定义类,您将在您的关卡中运行所有这些,并且当您的魔法方法无法解析时,它将回退到Yii。
此外,我会调查行为,因为您可以将许多常用函数委派给行为类。
使用组件行为
组件支持mixin模式,可以附加一个或多个行为。行为是一种对象,其方法可以通过收集功能而不是专门化(即正常的类继承)由其附加组件“继承”。组件可以附加多个行为,从而实现“多重继承”。
行为类必须实现IBehavior
接口。大多数行为都可以从CBehavior
基类扩展。如果行为需要附加到模型,它也可以从CModelBehavior或CActiveRecordBehavior扩展,这实现了模型的特定功能。
要使用行为,必须首先通过调用行为的attach()
方法将其附加到组件。然后我们可以通过组件调用行为方法:
// $name uniquely identifies the behavior in the component
$component->attachBehavior($name,$behavior);
// test() is a method of $behavior
$component->test();
可以像组件的普通属性一样访问附加行为。例如,如果名为tree的行为附加到组件,我们可以使用以下命令获取对此行为对象的引用:
$behavior=$component->tree;
// equivalent to the following:
// $behavior=$component->asa('tree');
可以暂时禁用某个行为,以便通过该组件无法使用其方法。例如,
$component->disableBehavior($name);
// the following statement will throw an exception
$component->test();
$component->enableBehavior($name);
// it works now
$component->test();
附加到同一组件的两个行为可能具有相同名称的方法。在这种情况下,第一个附加行为的方法将优先。
与events一起使用时,行为更加强大。当附加到组件时,行为可以将其某些方法附加到组件的某些事件。通过这样做,行为有机会观察或更改组件的正常执行流程。
还可以通过附加到的组件访问行为的属性。这些属性包括公共成员变量和通过行为的getter和/或setter定义的属性。例如,如果某个行为具有名为xyz的属性,并且该行为附加到组件$ a。然后我们可以使用表达式$a->xyz
来访问行为的属性。
更多阅读:
http://www.yiiframework.com/wiki/44/behaviors-events
http://www.ramirezcobos.com/2010/11/19/how-to-create-a-yii-behavior/