Select subset of properties from Doctrine entity for serialization - serialization

I am building a webservice that transmits json representations of domain models over a websocket connection. The entities are mapped with Doctrine, which unfortunately restricts me to only using protected or private properties in my entity classes. In order to include private properties in the json, I have been using this trait across my entities:
/**
* A trait enabling serialization for Doctrine entities for websocket transports.
* Unfortunately, this cannot be included in the abstract class for Doctrine entities
* as the parent class is unable to access private properties enforced by Doctrine.
*/
trait SerializableTrait
{
/**
* Implements {#link \JsonSerializable} interface.
* #return string - json representation
*/
public function jsonSerialize()
{
return get_object_vars($this);
}
}
However, the objects received on the client side should only contain a subset of the entity's properties to reduce load on the websocket connection and prevent sniffing of private information. Could this be realized elegantly in php without using the Reflection API or subclassing from a base class for client objects (i don't really want to split the entity class). Or is there maybe a way to use public properties in Doctrine entities that I am unware of? I am looking for something alone the lines of
$lightweightEntity = EntityStripper::strip($entity);
Thanks in advance!

Although initially not keen on using the Reflection API, it seems to be the only viable solution. So I came up with this solution parsing a custom #Serializable annotation to determine which properties are serialized:
use Doctrine\Common\Annotations\AnnotationReader;
use App\Model\Annotations\Serializable;
/**
* A trait enabling serialization of Doctrine entities for websocket transports.
*/
trait SerializableTrait
{
/**
* Implements {#link \JsonSerializable} interface and serializes all
* properties annotated with {#link Serializable}.
* #return string - json representation
*/
public function jsonSerialize()
{
// Circumvent Doctrine's restriction to protected properties
$reflection = new \ReflectionClass(get_class($this));
$properties = array_keys($reflection->getdefaultProperties());
$reader = new AnnotationReader();
$serialize = array();
foreach ($properties as $key) {
// Parse annotations
$property = new \ReflectionProperty(get_class($this), $key);
$annotation = $reader->getPropertyAnnotation($property, get_class(new Serializable()));
// Only serialize properties with annotation
if ($annotation) {
$serialize[$key] = $this->$key;
}
}
return json_encode($serialize, JSON_FORCE_OBJECT);
}
}

Related

How to define a Doctrine mappedSuperclass using XML or YAML instead of annotation mapping

The following script comes from https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html#mapped-superclasses, and was only changed to include a second sub-class. It is my understanding that MappedSuperclassBase cannot exist by itself but must be extended by one and only one sub-class (i.e. either EntitySubClassOne or EntitySubClassTwo), and is the same concept as supertype/subtype for SQL. Agree?
How is a super/sub type defined using either YAML or XML instead of annotation mapping?
<?php
/** #MappedSuperclass */
class MappedSuperclassBase
{
/** #Column(type="integer") */
protected $mapped1;
/** #Column(type="string") */
protected $mapped2;
/**
* #OneToOne(targetEntity="MappedSuperclassRelated1")
* #JoinColumn(name="related1_id", referencedColumnName="id")
*/
protected $mappedRelated1;
// ... more fields and methods
}
/** #Entity */
class EntitySubClassOne extends MappedSuperclassBase
{
/** #Id #Column(type="integer") */
private $id;
/** #Column(type="string") */
private $name;
// ... more fields and methods
}
/** #Entity */
class EntitySubClassTwo extends MappedSuperclassBase
{
/** #Id #Column(type="integer") */
private $id;
/** #Column(type="string") */
private $name;
// ... more fields and methods
}
Based on our comments, I think I see your confusion. Because the docs handle both "MappedSuperclass" and "Discriminator" on the same page, I think you've mixed up their uses in your head. Hopefully this can help you:
A MappedSuperclass provides properties/defaults in a re-usable way, but it can never be an Entity by itself. This is comparable to PHP's abstract classes (which cannot be instantiated on their own)
A Discriminator provides the ability to "extend" an Entity, making it another Entity. For example, having a Person Entity gives you 1 Entity. This Entity can be extended, for example by Worker and Manager.
A good use-case for a MappedSuperclass would be an AbstractEntity. Every Entity needs an ID, a unique identifier. It also gives you something common to check against in Listeners and such. So, go ahead and create:
/**
* #ORM\MappedSuperclass
*/
abstract class AbstractEntity
{
/**
* #var int
* #ORM\Id
* #ORM\Column(name="id", type="integer", options={"unsigned":true})
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
protected $id;
// getter / setter
}
See how this is both declared abstract and MappedSuperclass?
This is because neither (abstract class and MappedSuperclass) cannot be instantiated on their own. You cannot do $entity = new AbstractEntity() because it's an abstract PHP class. Neither will Doctrine create a separate table for AbstractEntity.
Next, create a Person:
/**
* #ORM\Entity
* #ORM\Table(name="persons")
*
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
*/
class Person extends AbstractEntity
{
/**
* #var string
* #ORM\Column(name="name", type="string", length=255, nullable=false)
*/
protected $name;
// getter / setter
}
The above, Person, Entity is setup for Class Table Inheritance through the JOINED inheritance type. Meaning that, on the database level, the table persons will be separate from any columns added by other entities, extending Person.
Notice how I did not declare DiscriminatorMap. Below from the docs, highlighted in bold by me:
Things to note:
The #InheritanceType, #DiscriminatorColumn and #DiscriminatorMap must be specified on the topmost class that is part of the mapped entity hierarchy.
The #DiscriminatorMap specifies which values of the discriminator column identify a row as being of which type. In the case above a value of "person" identifies a row as being of type Person and "employee" identifies a row as being of type Employee.
The names of the classes in the discriminator map do not need to be fully qualified if the classes are contained in the same namespace as the entity class on which the discriminator map is applied.
If no discriminator map is provided, then the map is generated automatically. The automatically generated discriminator map contains the lowercase short name of each class as key.
Now, let's create a Worker:
/**
* #ORM\Entity
* #ORM\Table(name="workers")
*/
class Worker extends Person
{
/**
* #var int
* #ORM\Column(name="worker_id", type="integer", length=11, nullable=false)
*/
protected $workerId;
// getter / setter
}
So, now we've got:
MappedSuperclass: AbstractEntity - is not a stand-alone Entity
Discriminated: Person - is a stand-alone Entity
"normal": Worker - extends Person
Things to note:
A MappedSuperclass can not be instantiated. As such: you can not create links/relations to it. Comparable with PHP's abstract class
A Discriminated Entity is one which also stands alone and can be used as a normal Entity. You can create relations to and from it, without an issue
An Entity extending a Discriminated Entity is an instance of both. In the above code these are both true: $worker instanceof Worker and $worker instanceof Person, because the Worker extends Person. However, $person instanceof Worker will be false!
$workerId = $person->getWorkerId() // generates "method does not exist" fatal
$workerId = $worker->getWorkerId() // generates integer value
Hope that managed to clear stuff up for you. If not, feel free to ask.

Doctrine not linking to owning object when adding to ArrayCollection

I have a problem when attempting to create a new Requirement object on my website. In my Requirement object I have the following Doctrine field:
/**
* #ORM\OneToMany(targetEntity="Verification", mappedBy="requirement", cascade="persist", orphanRemoval=true)
*/
private $verifications;
and I have the following method:
public function addVerification($verification) {
$this->verifications->add($verification);
}
In the constructor of the object I initialize the ArrayCollection:
/**
* Constructor
*/
public function __construct() {
parent::__construct();
$this->verifications = new ArrayCollection();
}
However, when attempting to create a new Requirement object everything works fine except that the Verifications that are created are not linked to the Requirement object. Both the Requirement object and the corresponding Verification objects are inserted into the database, but the requirement_id field for the Verification objects are NULL.
Do I need to manually set the requirement field in my Verification object? Does Doctrine not do this for me automatically when I use the add method for the ArrayCollection?
No they arent necessarily updated. If you have bi-directional relationships you must maintain the non-owing side yourself. You can read up on this in the documentation:
http://docs.doctrine-project.org/en/2.1/reference/association-mapping.html
Its hard for me to give you specifics without seeing both the Requirement and Verification definitions.

Design choices to remove if-is statements

Say i have a class hierarchy of domain objects with one base class and a couple of child classes, one level.
Let say I have a list of those objects (list of the base class) and I want to apply some logic to the classes that I feel don't really belong to the classes (eg. design/UI specific code).
What are my alternatives ?
If-is statement. Personally this one shouldn't even be considered as an alternative but i write it anyway.
Polymorphism. This one is actually an alternative in some cases but with my example above, I don't want my classes to contain any UI specifics.
Resolving some logic method via reflection/IoC container based on the type of the object.
Eg C#. Type type = typeof(ILogic<>).MakeGenericType(domainObject.GetType());
I really like this one, I don't get any compile time checks though if an implementation is missing for a sub class, or is that possible somehow?
Visitor pattern. Will work but seemes kind of overkill to apply on a structure thats only one level deep.
Anyone has any other tips or tricks to solve these kinds of problems?
Great question. Problem is that there are many solutions and most of them will work.
I work with MVC a lot, similar situation happens quite often. Especially in the view, when similar rendering needs to happen across some views... but does not really belong to the view.
Let's say we have child class ChildList that extends BaseList.
Add a property uiHandler in the child class. Overload the rendering function, let's say toString(), and use the uiHandler with your specific UI/Design things.
I wrote a little something, it is in PHP... but you should be able to get an idea. It gives you freedom to chose how your objects will be displayed and flexibility to use specific UIs for specific objects.
Look at the code below, it seems like a lot but int's not that bad.
BaseList - your base class
BaseListUIExtended - base class that uses UI, takes optional UI class as constructor parameter. In C# 4 you can use optional, otherwise use 2 constructors.
UIBase - interface for UI classes...
UIChildSpecific - UI class
ChildList - child class that can use UI or not, because of BaseListUIExtended optional constructor parameter.
Define interface
/**
* Base UI interface
*/
interface IUIBase {
/**
* Renders the Base Class
*
* #param UIBase $obj
* #return string
*/
public function render($obj);
}
Define base classes, child class
//**************************************************************
// Define Base Classes
//**************************************************************
/**
* Base Class
*/
class BaseList {
/**
* List of items
* #var array
*/
protected $_items = array();
/**
* Gets collection of items
*
* #return array
*/
public function getItems() {
return $this->_items;
}
/**
* Adds new item to the list
* #param object $item
*/
public function add($item) {
$this->_items[] = $item;
}
/**
* Displays object
*/
public function display() {
echo $this->toString();
}
/**
* To String
*/
public function __toString() {
// Will output list of elements separated by space
echo implode(' ', $this->_items);
}
}
/**
* Extended BaseList, has UI handler
* This way your base class stays the same. And you
* can chose how you create your childer, with UI or without
*/
class BaseListUIExtended extends BaseList {
/**
* UI Handler
* #var UIBase
*/
protected $_uiHandler;
/**
* Default Constructor
*
* #param UIBase Optional UI parameter
*/
public function __construct($ui = null) {
// Set the UI Handler
$this->_uiHandler = $ui;
}
/**
* Display object
*/
public function display() {
if ($this->_uiHandler) {
// Render with UI Render
$this->_uiHandler->render($this);
} else {
// Executes default BaseList display() method
// in C# you'll have base:display()
parent::display();
}
}
}
//**************************************************************
// Define UI Classe
//**************************************************************
/**
* Child Specific UI
*/
class UIChildSpecific implements UIBase {
/**
* Overload Render method
*
* Outputs the following
* <strong>Elem 1</strong><br/>
* <strong>Elem 2</strong><br/>
* <strong>Elem 3</strong><br/>
*
* #param ChildList $obj
* #return string
*/
public function render($obj) {
// Output array for data
$renderedOutput = array();
// Scan through all items in the list
foreach ($obj->getItems() as $text) {
// render item
$text = "<strong>" . strtoupper(trim($text)) . "</strong>";
// Add it to output array
$renderedOutput[] = $text;
}
// Convert array to string. With elements separated by <br />
return implode('<br />', $renderedOutput);
}
}
//**************************************************************
// Defining Children classes
//**************************************************************
/**
* Child Class
*/
class ChildList extends BaseListUIExtended {
// Implement's logic
}
Testing...
//**************************************************************
// TESTING
//**************************************************************
// Test # 1
$plainChild = new ChildList();
$plainChild->add("hairy");
$plainChild->add("girl");
// Display the object, will use BaseList::display() method
$plainChild->display();
// Output: hairy girl
// Test # 2
$uiChild = new ChildList(new UIChildSpecific());
$uiChild->add("hairy");
$uiChild->add("girl");
// Display the object, will use BaseListUIExtended::display() method
$uiChild->display();
// Output: <strong>hairy</strong><br /><strong>girl</strong>

Sending an Interface definition over the wire (WCF service)

I have a WCF service that generates loads Entity Framework objects (as well as some other structs and simple classes used to lighten the load) and sends them over to a client application.
I have changed 2 of the classes to implement an interface so that I can reference them in my application as a single object type. Much like this example:
Is it Possible to Force Properties Generated by Entity Framework to implement Interfaces?
However, the interface type is not added to my WCF service proxy client thingymebob as it is not directly referenced in the objects that are being sent back over the wire.
Therefore in my application that uses the service proxy classes, I can't cast or reference my interface..
Any ideas what I'm missing?
Here's some example code:
//ASSEMBLY/PROJECT 1 -- EF data model
namespace Model
{
public interface ISecurable
{
[DataMember]
long AccessMask { get; set; }
}
//partial class extending EF generated class
//there is also a class defined as "public partial class Company : ISecurable"
public partial class Chart : ISecurable
{
private long _AccessMask = 0;
public long AccessMask
{
get { return _AccessMask; }
set { _AccessMask = value; }
}
public void GetPermission(Guid userId)
{
ChartEntityModel model = new ChartEntityModel();
Task task = model.Task_GetMaskForObject(_ChartId, userId).FirstOrDefault();
_AccessMask = (task == null) ? 0 : task.AccessMask;
}
}
}
//ASSEMBLY/PROJECT 2 -- WCF web service
namespace ChartService
{
public Chart GetChart(Guid chartId, Guid userId)
{
Chart chart = LoadChartWithEF(chartId);
chart.GetPermission(userId); //load chart perms
return chart; //send it over the wire
}
}
Interfaces won't come across as separate entities in your WSDL - they will simply have their methods and properties added to the object that exposes them.
What you want to accomplish you can do using abstract classes. These will come across as distinct entities.
Good luck. Let us know how you decided to proceed.

Accessing more than one data provider in a data layer

I'm working on a business application which is being developed using DDD philosophy. Database is accessed through NHibernate and data layer is implemented using DAO pattern.
The UML class diagram is shown below.
UML Class Diagram http://img266.imageshack.us/my.php?image=classdiagramhk0.png
http://img266.imageshack.us/my.php?image=classdiagramhk0.png
I don't know the design is good or not. What do you think?
But the problem is not the design is good or not. The problem is after starting up the application an IDaoFactory is instantiated in presentation layer and send as parameter to presenter classes(which is designed using MVC pattern) as below
...
IDaoFactory daoFactory = new NHibernateDaoFactory(); //instantiation in main class
...
SamplePresenterClass s = new SamplePresenterClass(daoFactory);
...
Using just one data provider (which was just one database) was simple. But now we should get data from XML too. And next phases of the development we should connect to different web services and manipulate incoming and outgoing data.
The data from XML is going to be got using a key which is an enum. We add a class named XMLLoader to the data layer and add an interface ILoader to the domain. XMLLoader has a method whose signature is
List<string> LoadData(LoaderEnum key)
If we instantiate ILoader with XMLLoader in presentation layer as below we have to send it to objects which is going to get some XML data from data layer.
ILoader loader = new XMLLoader();
SamplePresenterClass s = new SamplePresenterClass(daoFactory, xmlLoader);
After implementing web service access classes
SamplePresenterClass s = new SamplePresenterClass(daoFactory, xmlLoader, sampleWebServiceConnector1, sampleWebServiceConnector2, ...);
The parameters is going to be grown in time. I think i can hold all instances of data access objects in a class and pass it to required presenters (maybe singleton pattern can helps too). In domain layer there must be a class like this,
public class DataAccessHolder
{
private IDaoFactory daoFactory;
private ILoader loader;
...
public IDaoFactory DaoFactory
{
get { return daoFactory; }
set { daoFactory = value; }
}
...
}
In main class the instantiation can be made with this design as follows
DataAccessHolder dataAccessHolder = new DataAccessHolder();
dataAccessHolder.DaoFactory = new NHibernateDaoFactory();
dataAccessHolder.Loader = new XMLLoader();
...
SamplePresenterClass s = new SamplePresenterClass(dataAccessHolder);
What do you think about this design or can you suggest me a different one?
Thanks for all repliers...
IMO, it would be cleaner to use a "global" or static daoFactory and make it generic.
DaoFactory<SamplePresenterClass>.Create(); // or
DaoFactory<SamplePresenterClass>.Create(id); // etc
Then, you can define DaoFactory<T> to take only, say, IDao's
interface IDao
{
IDaoProvider GetProvider();
}
interface IDaoProvider
{
IDao Create(IDao instance);
void Update(IDao instance);
void Delete(IDao instance);
}
Basically instead of passing every constructor your DaoFactory, you use a static generic DaoFactory. Its T must inherit from IDao. Then the DaoFactory class can look at the T provider at runtime:
static class DaoFactory<T> where T : IDao, new()
{
static T Create()
{
T instance = new T();
IDaoProvider provider = instance.GetProvider();
return (T)provider.Create(instance);
}
}
Where IDaoProvier is a common interface that you would implement to load things using XML, NHibernate, Web Services, etc. depending on the class. (Each IDao object would know how to connect to its data provider).
Overall, not a bad design though. Add a bit more OO and you will have a pretty slick design. For instance, each file for the XmlEnums could be implemented as IDao's
class Cat : IDao
{
IDaoProvider GetProvider()
{
return new XmlLoader(YourEnum.Cat);
}
// ...
}