动态创建Yii FormModel对象(CFormModel)

Pet*_*erG 5 php forms class yii magic-methods

我正在开发一个涉及以高抽象水平生成表单的应用程序(这是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
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

我要这样做如下:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

并在需要时调用它,如下所示:

$myModelObj = new MyFormModel($attr, $rules);
Run Code Online (Sandbox Code Playgroud)

在哪里:

$attr = array(
            'username',
            'rememberMe',
            'password',
        );
$rules = array(
            array('username, password', 'required'),
            array('rememberMe', 'boolean'),
            array('password', 'authenticate'), // assume function authenticate defined elsewhere
        );
Run Code Online (Sandbox Code Playgroud)

请注意,在我要完成的工作中,没有在任何文件中编写“ LoginClass”,而是在代码中即时创建的。

这将允许我创建表单(在视图中),执行以下操作:

// based on http://www.yiiframework.com/doc/guide/1.1/en/form.view
<?php echo $wForm->textField($myModelObj,'username'); ?>
Run Code Online (Sandbox Code Playgroud)

等等

我已经尝试过了,而$ this-> {$ attr}行却失败了:

Property "MyFormModel.username" is not defined.
Run Code Online (Sandbox Code Playgroud)

实际上,该行的代码如下:

$this->{$attr};
Run Code Online (Sandbox Code Playgroud)

??? 表示我不太确定要为此分配什么。在Yii doc示例中,它们只是将字段定义为公共类变量。

我应该使用魔术方法吗?

我在这里尝试做的事情甚至可能吗?

Pen*_*m10 5

如您所知,Yii使用OOP重载来解析类似AR的属性。

您需要在此处执行的操作类似于Yii内部执行的操作。

定义一个硬编码属性,以将所有自定义属性存储为数组: $_data

并且此数据将是一个数组,并将保存您在运行时添加的所有属性。您可能需要像Yii一样通过覆盖魔术方法(setter,getters,isset)来挑战验证,以便首先从$_data财产持有人那里解析财产名称。

您将在CActiveRecord中找到某种代码来查找所有__XXX类似方法。

如果将AR属性处理复制到自定义类,则所有这些操作都将在您的级别上运行,并且在您的魔术方法无法解决时,将回到Yii。

另外,我会研究“行为”,因为您可以将许多常用功能委托给行为类。

组件行为的使用

组件支持mixin模式,并且可以通过一个或多个行为进行附加。行为是一个对象,其对象可以通过收集功能而不是专门化(即常规类继承)的方式由其附加组件“继承”。一个组件可以附加多种行为,从而实现“多重继承”。

行为类必须实现IBehavior接口。大多数行为可以从CBehavior基类扩展。如果需要将行为附加到模型,则它也可以从CModelBehaviorCActiveRecordBehavior扩展,后者为模型实现了特定的功能。

要使用行为,必须首先通过调用行为的attach()方法将其附加到组件。然后我们可以通过组件调用行为方法:

// $name uniquely identifies the behavior in the component
$component->attachBehavior($name,$behavior);
// test() is a method of $behavior
$component->test();
Run Code Online (Sandbox Code Playgroud)

可以像组件的常规属性一样访问附加的行为。例如,如果将名为tree的行为附加到组件,则可以使用以下方法获取对此行为对象的引用:

$behavior=$component->tree;
// equivalent to the following:
// $behavior=$component->asa('tree');
Run Code Online (Sandbox Code Playgroud)

可以暂时禁用行为,以使该方法无法通过组件使用。例如,

$component->disableBehavior($name);
// the following statement will throw an exception
$component->test();
$component->enableBehavior($name);
// it works now
$component->test();
Run Code Online (Sandbox Code Playgroud)

附加到同一组件的两个行为可能具有相同名称的方法。在这种情况下,第一个附加行为的方法将优先。

当与事件一起使用时,行为将更加强大。将行为附加到组件时,可以将其某些方法附加到组件的某些事件。这样,该行为就有机会观察或更改组件的正常执行流程。

行为的属性也可以通过其附加到的组件进行访问。这些属性包括公共成员变量和通过行为的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/