【问题标题】:Returning virtual columns in Phalcon models在 Phalcon 模型中返回虚拟列
【发布时间】:2014-12-23 10:36:00
【问题描述】:

我有一个模型 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'));
    }
}

【问题讨论】:

    标签: php model phalcon


    【解决方案1】:

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

    【讨论】:

    • 这正是我所追求的。谢谢你非常彻底的回答。非常感谢。 b.
    • 为了规避这种 Phalcon 在 toArray() 中不包含虚拟字段的“限制”,我在这里提供了一个解决方案:stackoverflow.com/a/45555178/466395
    • 链接已过期。这个方法还有效吗?
    【解决方案2】:

    为虚拟字段重写 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;
    }
    

    第二步

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

    public $list_virtual_fields = [
        'status_label'
    ];
    

    您还应该为这些虚拟字段定义类属性、setter 和 getter。只是一个例子:

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

    第三步

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

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

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

    【讨论】:

      猜你喜欢
      • 2021-11-25
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多