Reputation: 13321
My object array is not deserializing when loading the entity from the database.
I have a non-entity object named NetworkAddress
. Then in my Foo
entity, I have an array of these network addresses.
The network addresses are being saved as serialized PHP in the database, but when I load the object, the data for the network addresses aren't being added.
/**
* @ORM\Entity(repositoryClass="App\Repository\FooRepository")
*/
class Foo implements \Serializable
{
...
/**
* @var NetworkAddress[]
* @Groups({"main", "initialized"})
* @ORM\Column(type="array")
*/
private array $addresses;
...
So when I load my $foo
object, $foo->getAddresses()
returns an array of empty NetworkAddresses
, even though the raw database values is this:
a:1:{i:0;C:22:"App\DTO\NetworkAddress":41:{a:2:{i:0;s:9:"127.0.0.1";i:1;s:4:"5000";}}}
I'm using a basic ->findOneBy()
command on my repo to retrieve the object.
Serializing seems to work, but is there something special for deserializing an object stored as an array?
Here's my NetworkAddress class, w/o the getters/setters
class NetworkAddress implements \Serializable
{
/**
* @Groups({"main", "initialized"})
* @Assert\Regex(
* pattern="/^[0-9A-z\.-]+$/",
* match=true,
* message="Invalid host format."
* )
*/
private string $host = 'localhost';
/**
* Intentionally left untyped so we can accept int or string for port number.
*
* @Groups({"main", "initialized"})
* @Assert\NotBlank(message = "Port should not be empty.")
* @Assert\Range(min="1", max="65535", invalidMessage="Invalid port.")
*/
private $port;
Upvotes: 0
Views: 147
Reputation: 690
You can check the following, associate to deserialization problem on array of objects, and "safe php serialization" to fix up the vulnerability issue on php serialization.
class Foo implements \Serializable
{
//...
protected $addresses;
//...
public function __construct($addresses = null) {
if (!is_null($addresses)) {
{
$this->addresses = $addresses;
}
}
/* serialize network addresses */
public function serialize(): string {
/* sanitize for any recursion */
if ($class = $this->checkRecursion()) {
throw new \Exception("Recursion detected: '$class'");
}
return serialize($this->addresses);
}
/* deserialize network addresses */
public function unserialize($serialized): void {
$this->addresses = unserialize($serialized);
/* sanitize for any recursion */
if ($class = $this->checkRecursion()) {
throw new \Exception("Recursion detected: '$class'");
}
}
/* check recursion function */
protected function checkRecursion() {
$class = print_r($this, true);
if (preg_match('/[^\=\>]+(?=\*RECURSION\*)/i', $class, $matches)) {
return trim($matches[0]);
}
return false;
}
}
Class NetworkAddress:
class NetworkAddress implements \Serializable
{
protected $netAddress ;
public function __construct($netAddress = ['host' => '127.0.0.7', 'port' => 7007]) {
if (!is_null($netAddress)) {
$this->netAddress = $netAddress;
}
}
/* get class property by name
eg. $net->__get('netAddress');
*/
public function __get($name) {
return $this->$name;
}
/* set class property from name
eg. $net->__set('netAddress', ['host' => 'localhost', 'port' => '8080']);
*/
public function __set($name, $value) {
$this->$name = $value;
}
/* safe serialize */
public function serialize(): string {
/* sanitize for any recursion */
if ($class = $this->checkRecursion()) {
throw new \Exception("Recursion detected: '$class'");
}
return serialize($this->netAddresses);
}
/* safe unserialize */
public function unserialize($serialized): void {
$this->netAddresses = unserialize($serialized);
/* sanitize for any recursion */
if ($class = $this->checkRecursion()) {
throw new \Exception("Recursion detected: '$class'");
}
}
/* check recursion function */
protected function checkRecursion() {
$class = print_r($this, true);
if (preg_match('/[^\=\>]+(?=\*RECURSION\*)/i', $class, $matches)) {
return trim($matches[0]);
}
return false;
}
}
Calls example:
/* create new network adresses */
$addresses = [new NetworkAddress(['host' => 'localhost', 'port' => 8080]), new NetworkAddress(['host' => 'example.com', 'port' => 80])];
/* create new foo */
$foo1 = new Foo($addresses);
/* serialize foo object */
$serialized = serialize($foo1);
/* unserialized foo object */
$foo2 = unserialize($serialized);
Hope this helps.
Upvotes: 1