Reputation: 516
I have a model leads_contents_interactions
for the (simplified) table:
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;
I would like to select these and in addition to the id
, lead_content_id
, and created_on
columns, I would also like it to return a column is_new
where that is something like this:
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;
Now I am aware I can do this with PHQL, but the leads_contents_interactions
would ideally not be queried directly, I want this extra column to be returned when it is queried naturally like:
$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;
}
}
Model for Lead (simplified)
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')
);
}
}
Model for LeadsContents (simplified)
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');
}
}
Model for LeadsContentsInteractions (simplified)
class LeadsContentsInteractions extends PersendlyModelAbstract {
public function initialize() {
$this->belongsTo('lead_content_id', 'LeadsContents', 'id', array('alias' => 'lead_content'));
}
}
Upvotes: 2
Views: 2201
Reputation: 1966
In response to what David Duncan said:
It should however be noted, that if you then use the method toArray() on the record set, that it will only use the columns that exist on the table itself.
And to circumvent such Phalcon 'limitation', I created the following method override.
Basically, create a BaseModel.php and put the next code there.
/**
* 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;
}
Then, in any of your app models, define the list of virtual fields that will be included in the method override above. For example:
public $list_virtual_fields = [
'status_label'
];
You should also define class properties, setters, and getters for those virtual fields. Just an example:
protected $status_label;
public function getStatusLabel() {
return $this->status_label;
}
public function setStatusLabel(string $status_label) {
$this->status_label = $status_label;
return $this;
}
Finally, set the value of virtual fields throughout your app. An example:
public function afterFetch() {
$this->setStatusLabel('pending');
}
Note that my code uses getters and setters. You could change that if you wish.
Upvotes: 2
Reputation: 1858
If you are wanting to add a column that doesn't exist on the table, but exists as a business rule (created_on > DATE_SUB(NOW(),INTERVAL 1 DAY), 1, 0) then you need to add that rule in the afterFetch method of the model itself:
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
}
}
It should however be noted, that if you then use the method toArray() on the record set, that it will only use the columns that exist on the table itself.
http://forum.phalconphp.com/discussion/498/afterfetch-
Upvotes: 4