Is there a way for the model to compute a field before save?
I have a schema something like this:
item_id
item_qty
item_price
linetotal
I'm trying to avoid this kind of code in my controller:
$model->linetotal = $f3->get('POST.item_qty') * $f3->get('POST.item_price');
$model->save();
Instead, I want to setup my model to compute the linetotal
before save.
Perhaps something like the beforeSave
callback in cakephp, or even better maybe I missed that I can set it up just like a Mapper virtual field on f3, except its a real field...
What you're asking for has just been released in 3.2.2. DB mappers now come with the following hooks: beforeinsert
, afterinsert
, beforeupdate
, afterupdate
, beforeerase
, aftererase
and onload
.
So you could implement the linetotal
calculation like this:
class myModel extends \DB\SQL\Mapper {
static function _beforeupdate($self,$pkeys) {
$self->linetotal = $self->item_qty * $self->item_price;
}
function __construct() {
$f3=\Base::instance();
parent::construct($f3->get('DB'),'mytable');
$this->beforeupdate(array(__CLASS__,'_beforeupdate'));
}
}
But since the calculation is also relevant for INSERT statements, you'll also need to hook the beforeinsert
event. You could use the same function to hook both events :
class myModel extends \DB\SQL\Mapper {
static function _linetotal($self,$pkeys) {
$self->linetotal = $self->item_qty * $self->item_price;
}
function __construct() {
$f3=\Base::instance();
parent::construct($f3->get('DB'),'mytable');
$this->beforeinsert(array(__CLASS__,'_linetotal'));
$this->beforeupdate(array(__CLASS__,'_linetotal'));
}
}
NB: an alternative way to implement the linetotal
calculation would be to simply override the mapper set()
method:
class myModel extends \DB\SQL\Mapper {
function set($key,$val) {
parent::set($key,$val);
if ($key=='item_qty' || $key=='item_price')
$this->linetotal = $this->item_qty * $this->item_price;
}
}
I forgot a third alternative, which actually looks more appropriate in your case: virtual fields. In this case, the calculation is left to the DB engine. E.g:
class myModel extends \DB\SQL\Mapper {
function __construct(){
$f3=\Base::instance();
parent::construct($f3->get('DB'),'mytable');
$this->linetotal = 'item_qty * item_price';
}
}
PS: don't forget to remove the linetotal
field from your database.