The background:
Developer needs a way of telling Phalcon serializer which Model properties should be included in serialization.
Implement:
Phalcon\Mvc\Model::serializableProperties = array();
Sample code:
class Country extends Phalcon\Mvc\Model
{
protected $serializableProperties = [
'states' // Include in serialization.
];
protected $states; // Not a table field, some custom property
public function initialize()
{
$this->setSource('countries');
}
public function afterFetch()
{
if ($this->id) {
$this->states = ['AL', 'AZ', 'NV', 'NY'];
}
}
}
Thanks!
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
Why not
public function __sleep()
{
return array('states');
}
?
See http://www.php.net/manual/en/language.oop5.magic.php#object.sleep
@sjinks I've just tried that - added __sleep() to Country. Result is exactly the same. __sleep() is not invoked at all (my debugbreak() is not firing).
Ah, I see — Model implements Serializable interface.
To serialize your own properties (which \Phalcon\Mvc\Model is unaware of), you will need to use a trick like this: http://ua1.php.net/manual/en/class.serializable.php#107194
public function serialize()
{
$data = array(
'states' => $this->states,
'parent' => parent::serialize(),
);
return serialize($data);
}
public function unserialize($str)
{
$data = unserialize($str);
parent::unserialize($data['parent']);
unset($data['parent']);
foreach ($data as $key => $value) {
$this->$key = $value;
}
}
Thanks, that did the trick:
public function serialize()
{
$data = [
'parent' => parent::serialize()
];
if ($this->serializableProperties) {
foreach ($this->serializableProperties as $k => $v) {
$data[$v] = $this->$v;
}
}
return serialize($data);
}
What's your opinion on the original NFR? Listing keys to serialize is definitely easier and removes overhead.
I wouldn't put serializableProperties on the same model, maybe in a new category of ModelsMetaData
@phalcon ModelsMetaData is practically undocumented. Can you give me a hint on how to implement it?
Guys,
I would like to return to this item for a second.
Would you be so kind explaining why wouldn't Phalcon serialize all properties of a model class? I understand that a programmer may assign a Closure to Model property and so on. What is the REAL reason it behaves that way.
I'll tell you where I'm coming from. I have a Model that nests another model, which in turn may nest more models. Think about Layout->Form->Section->Page->RadioQuestion->Options hierarchy. Serialization of Layout incurs serialization of nested objects.
Long story short - using the trick outlined above really hurts the performance.
return serialize($data); is being called often enough to shoot high in the profiler. Wouldn't it be better if Phalcon serializer took care of everything?
Thanks!
@phalcon @sjinks
Sorry to bug you again, but this is a kind of sore point for me. Can I have your thoughts, please?
Why wouldn't you by default serialize everything (including non-model fields), except the object properties that are known to Phalcon?
Thanks!
@phalcon @sjinks
I will second @temuri416 inquiry about this topic as well. Excluding non phalcon model fields definitely limits flexibility on practical and common scenarios
I decided to revive this... Again! Too serious of a problem to ignore.
http://forum.phalconphp.com/discussion/1714/new-attempt-to-get-model-serializer-discussion-going
Posting here for posterity's sake. I recommend using the below approach, as opposed to the one suggested previously which involves calling the parent's serialize method - this leads to a lot of recursion / slow performance. Also, with the below you need only override serialize (and not unserialize). This is actually exactly what cphalcon is doing behind the scenes (per the source code)
public function serialize()
{
$metaData = $this->getModelsMetaData();
$fields = array_merge($metaData->getAttributes($this), array(
"_your_custom_property",
"_your_second_custom_property"
));
$data = array();
foreach($fields as $k) {
if (isset($this->{$k})) {
$data[$k] = $this->{$k};
}
}
return serialize($data);
}
Something like this would be great to have.
Thank you for contributing to this issue. As it has been 90 days since the last activity, we are automatically closing the issue. This is often because the request was already solved in some way and it just wasn't updated or it's no longer applicable. If that's not the case, please feel free to either reopen this issue or open a new one. We will be more than happy to look at it again! You can read more here: https://blog.phalconphp.com/post/github-closing-old-issues
Most helpful comment
Posting here for posterity's sake. I recommend using the below approach, as opposed to the one suggested previously which involves calling the parent's serialize method - this leads to a lot of recursion / slow performance. Also, with the below you need only override serialize (and not unserialize). This is actually exactly what cphalcon is doing behind the scenes (per the source code)