返回 Phalcon 模型中的虚拟列


Returning virtual columns in Phalcon models

我有一个(简化(表的模型leads_contents_interactions

CREATE TABLE `leads_contents_interactions` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `lead_content_id` bigint(20) unsigned DEFAULT NULL,
    `created_on` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=59 DEFAULT CHARSET=utf8;

我想选择这些,除了 idlead_content_idcreated_on 列之外,我还希望它返回一列is_new,如下所示:

SELECT 
    id,
    lead_content_id,
    created_on,
    IF(created_on > DATE_SUB(NOW(),INTERVAL 1 DAY), 1, 0) AS is_new
FROM leads_contents_interactions;

现在我知道我可以用 PHQL 做到这一点,但理想情况下不会直接查询leads_contents_interactions,我希望在自然查询时返回这个额外的列,如下所示:

$leads = $user->getRelated(
    'leads',
    array(
        'Lead.deleted_by IS NULL',
        'limit'=>1000
    )
);
foreach($leads as $lead) {
    foreach($lead->interactions as $interaction) {
        echo $interaction->id."'t".$interaction->is_new.PHP_EOL;
    }
}

潜在客户模型(简化(

class Lead extends PersendlyModelAbstract {
    public function initialize() {
        // A lead has multiple interactions, `contents`, through the weak entity `leads_contents`
        $this->hasManyToMany(
            'id',
            'LeadsContents',
            'lead_id',
            'id',
            'LeadsContentsInteractions',
            'lead_content_id',
            array('alias' => 'interactions')
        );
    }
}

潜在客户内容模型(简体(

class LeadsContents extends PersendlyModelAbstract {
    public function initialize() {
        $this->belongsTo('lead_id', 'Lead', 'id', array('alias' => 'lead'));
        $this->belongsTo('content_id', 'Content', 'id', array('alias' => 'content'));
        $this->hasMany('id', 'LeadsContentsInteractions', 'lead_content_id');
    }
}

潜在顾客内容交互模型(简化(

class LeadsContentsInteractions extends PersendlyModelAbstract {
    public function initialize() {
        $this->belongsTo('lead_content_id', 'LeadsContents', 'id', array('alias' => 'lead_content'));
    }
}
如果要

添加表中不存在但作为业务规则存在的列(created_on> DATE_SUB(NOW((,INTERVAL 1 DAY(,1,0(,则需要在模型本身的afterFetch方法中添加该规则:

http://docs.phalconphp.com/en/latest/reference/models.html#initializing-preparing-fetched-records

class LeadsContentsInteractions extends PersendlyModelAbstract 
{
    public $isNew;
    public function afterFetch()
    {
        $this->isNew = INSERT BUSINESS LOGIC HERE
    }
}

但是应该注意的是,如果随后在记录集上使用 toArray(( 方法,它将仅使用表本身上存在的列。

http://forum.phalconphp.com/discussion/498/afterfetch-

覆盖虚拟字段的 toArray(( 方法。

针对大卫·邓肯所说的话:

但是应该注意的是,如果您随后使用方法toArray(( 在记录集上,它将仅使用 表本身。

为了规避这种 Phalcon "限制",我创建了以下方法覆盖。

步骤 1

基本上,创建一个 BaseModel.php并将下一个代码放在那里。

/**
 * Method override.
 *
 * This method is inherited from Model::toArray()
 * https://docs.phalconphp.com/en/3.2/api/Phalcon_Mvc_Model
 *
 * We override it here to circumvent a Phalcon limitation:
 * https://stackoverflow.com/a/27626808/466395
 *
 * Basically, the limitation consists that, when one adds 'virtual fields' to a model (for example,
 * by way of callback methods like afterFetch()), then using toArray() on that model only returns
 * the fields in the database table but not the virtual fields.
 *
 * @access public
 * @param array $columns As per the Model::toArray() method.
 * @return array The data of the model, including any custom virtual fields.
 */
public function toArray($columns = null) {
    // calls the regular toArray() method
    $data = parent::toArray($columns);
    // then gets the model's virtual fields, if any
    $virtual_fields = [];
    if (!empty($this->list_virtual_fields)) {
        // iterates, to get the virtual field's name, value, and getter
        foreach ($this->list_virtual_fields as $name) {
            $getter_name = 'get' . 'Phalcon'Text::camelize($name);
            $virtual_fields[$name] = $this->{$getter_name}();
        }
    }
    // merges the model's database data with its virtual fields
    $data = array_merge($data, $virtual_fields);
    return $data;
}

步骤 2

然后,在任何应用模型中,定义将包含在上述方法重写中的虚拟字段列表。例如:

public $list_virtual_fields = [
    'status_label'
];

您还应该为这些虚拟字段定义类属性、资源库和 getter。举个例子:

protected $status_label;
public function getStatusLabel() {
    return $this->status_label;
}
public function setStatusLabel(string $status_label) {
    $this->status_label = $status_label;
    return $this;
}

步骤 3

最后,在整个应用程序中设置虚拟字段的值。举个例子:

public function afterFetch() {
    $this->setStatusLabel('pending');
}

请注意,我的代码使用 getter 和 setter。如果您愿意,您可以更改它。