Jump to content

Different views of entity objects using the JsonSerializable interface


Recommended Posts

I have an entity object which contains other entity objects which in turn contain other entity objects.  Of of these entity object implements ArrayAccess and contains a collection of entity objects.  All the properties in these objects are protected.

To get the applicable data, all of these objects implement JsonSerializable and include a jsonSerialize() method which cascade and to my amazement provide my exact desired stdClass which I convert to JSON and send to the client.

But now I need a different view of the object.  By different view, I mean a different sub-set of properties and potentially calling them different names.

How should this be accomplished?

I can obviously manually iterate over the object and manipulate it, but I am sure that doing so is the wrong approach.

Or maybe extend all of the objects and override jsonSerialize() in each?  This seems like a lot of work.

Ideally, I would have some public method on the top object like $topObject->getView1() which would return one stdClass, and $topObject->getView2() which would return another.  But I don't understand how this cascading of nested objects into their parents would work as I can only have one jsonSerialize() in each class.  Maybe passing jsonSerialize() a value somehow gets passed to its children objects?  Sounds prone to error, but maybe not.

Any thoughts?  Thank you

Link to comment
Share on other sites

The following will not work as the injected view doesn't have viability.  Maybe some derivative of this approach? 

<?php

class ParentClass implements \JsonSerializable
{

    private $collection, $node1, $node2, $view;

    public function __construct($collection, $serializable1, $serializable2, $view=false)
    {
        $this->collection = $collection;
        $this->serializable1 = $serializable1;
        $this->serializable2 = $serializable2;
        $this->view = $view;
    }

    public function jsonSerialize()
    {
        return $this->view?$this->view->view($this):[
            'serialized' => $this->collection,
            'serializable1' => $this->serializable1
        ];
    }

}

class NestedSerializable implements \JsonSerializable
{

    private $serializable1, $serializable2, $serializable3, $view;

    public function __construct($serializable1, $serializable2, $serializable3, $view=false)
    {
        $this->serializable1 = $serializable1;
        $this->serializable2 = $serializable2;
        $this->serializable3 = $serializable3;
        $this->view = $view;
    }

    public function jsonSerialize()
    {
        return $this->view?$this->view->view($this):[
            'serialized1' => $this->serializable1,
            'bla' => $this->serializable3,
        ];
    }

}

class SerializableCollection implements \JsonSerializable {

    private $elements;

    public function __construct(array $elements, $view=false)
    {
        $this->elements = $elements;
        $this->view = $view;
    }

    public function jsonSerialize()
    {
        return $this->elements;
    }

}

$obj=new ParentClass(
    new SerializableCollection([
        new NestedSerializable(null,null,null),
        new NestedSerializable(null,null,null),
        new NestedSerializable(new NestedSerializable(null,null,null),null,null)
    ]),
    new NestedSerializable(null,null,null),
    new NestedSerializable(new NestedSerializable(null,null,null),null,null)
);

echo json_encode($obj).PHP_EOL.PHP_EOL;// Outputs: {"serialized":[{"serialized1":null,"bla":null},{"serialized1":null,"bla":null},{"serialized1":{"serialized1":null,"bla":null},"bla":null}],"serializable1":null}

class View1
{
    //public function __construct($that){$this->that = $that;}
    public function view($that) {
        return [
            'serialized1' => $that->serializable2,
            'blabla' => $that->serializable3,
        ];
    }

}
$obj=new ParentClass(
    new SerializableCollection([
        new NestedSerializable(null,null,null, new View1),
        new NestedSerializable(null,null,null, new View1),
        new NestedSerializable(new NestedSerializable(null,null,null, new View1),null,null, new View1)
    ]),
    new NestedSerializable(null,null,null, new View1),
    new NestedSerializable(new NestedSerializable(null,null,null, new View1),null,null, new View1)
);

echo json_encode($obj);

 

Link to comment
Share on other sites

Move the logic of serializing out of your entities. It does not belong there, nor should your properties be protected, they should be private. Only if absolutely necessary, can they be protected. And even then you can still create a protected getter/setter of some sort.

I already posted how to do the serializing in your other thread.

<?php

interface NodeSerializer {
  function serialize(Node $node);
  function unserialize($input, Node $node);
}

With this you can create as many 'views' as you need.

Link to comment
Share on other sites

With that said, perhaps you don't want to expose all properties. In that case you can also resort to using a Visitor

<?php

interface NodeVisitor {
  function visitNode(Node $node);
  function visitCategory(CategoryNode $node);
  // ...
}

final class Node {
  function accept(NodeVisitor $nodeVisitor) {
    $nodeVisitor->vistNode($this);
    foreach ($this->categories as $category) {
      $nodeVistor->visitCategory($category);
    }
  }
}

$node->accept($myNodeVisitor);
$json = $myNodeVisitor->getResult();

This is of course a little more difficult then using a simple serializer.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.