在Phalcon模型中返回虚拟列

时间:2014-12-23 10:36:00

标签: php model phalcon

我对(简化)表有一个模型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')
        );
    }
}

LeadsContents模型(简化)

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');
    }
}

LeadsContentsInteractions模型(简化)

class LeadsContentsInteractions extends PersendlyModelAbstract {

    public function initialize() {
        $this->belongsTo('lead_content_id', 'LeadsContents', 'id', array('alias' => 'lead_content'));
    }
}

2 个答案:

答案 0 :(得分:3)

如果您想要添加表中不存在的列,但作为业务规则存在(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-

答案 1 :(得分:1)

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

回应David Duncan所说的话:

  

但是应该注意,如果你然后使用方法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。如果你愿意,你可以改变它。