We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Model automagical encrypting/decrypting values

Hi guys,

Essentially what I'm looking to do is on a per-model basis, have a static array of 'Columns' that will be encrypted. I wanted to this in a simple manner that would be require developers to mess around with encrypting and decrypting values as they're needed.

I've got event handlers on beforeSave() and afterSave() handling the initial model creation which works fine, but trying to either:

A. Get these values decrypted 'on the fly' (as they're requested, ie. __get() magic method.)

B. Have the values decrypted upon the object being instantiated from a resultSet (find/findAll)

I've found that with A. you are not able to override the __get() magic method, because of how the framework is built (ref: https://github.com/phalcon/cphalcon/issues/1085 - Please note I don't think the 2 code patches are actually relevant to the proposed fixed)

So overall there's no way to be notified when a property value is requested for a Model. I was willing to settle for B.

However I've found that with B. it seems the only way to do this would be through overriding the find() and findAll() functions, there is event/behaviour that I could attach to for when an object has data 'loaded' against it, initialize() is too early in the models lifecycle, and all (documented) events are too late.

The reason I don't want to override find() & findAll() is because it could cause issues when using methods such as refresh() against the model, and also it's un-neccesarily decrypted data that may not even need to be referenced which seems like a waste of computing power and time.

Does anyone have any ideas on how to properly implement this? Is defining my own ModelManager or ResultSet the way to go?



98.9k
Accepted
answer

You can use afterFetch to decrypt the necessary columns after getting a record: https://docs.phalcon.io/en/latest/reference/models.html#initializing-preparing-fetched-records

Or you can simply add getters to lazily decrypt the fields once they are accessed:

<?php

class MyModel extends Phalcon\Mvc\Model
{

    protected $isDecrypted = false;

    protected $column;

    public function getMyColumn()
    {
        if (!$this->isDecrypted) {
            $this->column = my_decryption_func($this->column);          
            $this->isDecrypted = true;
        }
        return $this->column;
    }
}