How to set max depth in serialize context depending on request? - jmsserializerbundle

I have two request, first get list of objects and second get the Object. In Object entity there is a property OneToMany with other entity and #MaxDepth(2). I want to get depth 4 when list() request and keep depth in 2 when get() request. Is there a way to modify the max depth of a property depending on the request? I use Symfony2 JMSSerializer Bundle.
//Entity
/**
* #Expose
* #Serializer\MaxDepth(2)
* #ORM\OneToMany(targetEntity="GR\BonusBundle\Entity\Bonus", mappedBy="bonusRequestTrace")
*/
private $bonuses;
//Controller
$objView->setSerializationContext(SerializationContext::create()->enableMaxDepthChecks());

Related

TenantId is null when saving an entity in a Discriminator based multi tenant application in Grails 3.2 with GORM 6

I am trying to implement a MultiTenant application using GORM 6.0.0.RC2.
When a domain class that implements MultiTenant is saved via the GORM's save() method, the tenantId property is not set to the current tenantId. It is always null and hence fails validation. However Tenants.currentId() returns the correct tenant id based on the specified tenant resolver class.
Is it the application's responsibility to set the tenantId on an instance of the domain class when it is saved or will GORM take care of it by setting the property appropriately before being saved?
My Domain Person class
class Person implements MultiTenant<Person> {
String id
String tenantId
String name
}
and the code to save an instance of the Person class is
new Person(name: "pmohan").save(failOnError: true)
it always fails with a validation exception indicating tenantId is null.
But the tenant resolver according to the configuration below resolves to the right tenantId.
gorm:
multiTenancy:
mode: DISCRIMINATOR
tenantResolverClass: com.MyTenantResolver
Also the Tenants.currentId returns the value as expected. I was expecting the save() method to populate the tenantId property automatically based on MyTenantResolver class.

Doctrine entity to different json views

When I get a list of entities from Doctrine, how can I return different json 'views' ?
Ie. when I load Student classes I want views with only id, displayName and another with more details id, firstName, lastName, email, groups.
Groups is another collection with id, name.
I'm using lumen and doctrine.
You can implement JsonSerializable interface on your entityes and create custom versions on it.
ie:
class MyEntity implements JsonSerializable {
/**
* Doctrine annotation
*/
private $myEntityMember;
...
public function jsonSerialize() {
//serialize your entity here and use custom params to modify the serialized object output
}
}
This way you can call $myEntityObject->jsonSerialize() whenever you need.

How do I obtain all documents referenced by a single document?

If I have a document Shop that has many Activities defined as ReferenceMany, is there a way I can directly query for the list of Activities for a Shop without hydrating a Shop instance?
For example:
{
"_id": fd390j09afj09dfj,
"activities": [
...
]
}
All I want is to be able to say "get me the array activities where _id is fd390j09afj09dfj, and hydrate them as Activity instances.
Here's the first solution I came up with:
/**
* Gets all activities configured for a shop.
*
* #param string $shopId
* #return \BikeShed\Domain\Activity[]|\Doctrine\Common\Collections\ArrayCollection
*/
public function findByShopId($shopId) {
/** #var \BikeShed\Domain\Repository\Shop $shopRepository */
$shopRepository = $this->dm->getRepository('BikeShed\Domain\Shop');
$shop = $shopRepository->findOneById($shopId);
return $shop->getActivities();
}
It's simply fetching the Shop and then getting all the Activities via the defined relation.
Here's a working example of how you would implement jmikola's last suggestion:
/**
* #param string $shopId
* #return ActivityModel[]
*/
public function findByShopId($shopId) {
$partialShopData = $this->dm->getRepository('BikeShed\Domain\Shop')->createQueryBuilder()
->hydrate(false)
->field('activities')
->getQuery()
->getSingleResult()
;
$activityIds = [];
if(!empty($partialShopData['activities']))
foreach($partialShopData['activities'] as $activity)
if(!empty($activity['$id']))
$activityIds[] = $activity['$id'];
return $this->createQueryBuilder()
->field('id')
->in($activityIds)
->getQuery()
->toArray()
;
}
You cannot directly query the Shop collection or (or ODM repository) and receive Activity instances; however, you can use the Query Builder API to specify a projection with select('activities'). The executed query will still return Shop instances, but the activities field should be the only thing hydrated (as a PersistentCollection of Activity instances). In this case, you shouldn't modify any of the non-hydrated Shop fields, as ODM will detect any non-null value as a change.
It should be trivial to add a convenience method on ShopRepository that issues the above query with its select() and returns the collection (or an array) of Activity documents instead of the Shop. Keeping the Shop inaccessible should also protect you from inadvertently modifying other non-hydrated fields within it.
The down-side with this method is that the Activities will be proxy objects and lazily loaded. You can mitigate this with reference priming. With priming, you'll end up doing two queries (one for the Shop and one for all referenced Activity documents).
Regarding your follow-up question about putting this method on the Activity repository, you do have another option. Firstly, I agree that ActivityRepository::findByShopId() is preferable to calling a method on ShopRepository that returns Activity objects.
Each repository has a reference to the document manager, which you can use to access other repositories via the getRepository() method. An ActivityRepository::findByShopId() could do the following:
Access the Shop repository through the document manager
Query for the Shop by its ID, projecting only the activities field and disabling hydration completely
Collect the identifiers from the activities array. Depending on whether the Activity references are simple or not, the elements in that array may be the raw _id values or DBRef objects.
Execute a query for all Activity objects (easy, since we're already in that repository) where the ID is $in the array of identifiers

Why Doctrine 2 not have basic validate method that validate if all values fit entities attributes?

I am new with doctrine 2.
Why Doctrine 2 not have basic validate method that validate if all values fit entities attributes?
My question target to understand more how doctrine 2 works and why without say that something wrong in doctine 2. (Mostly because i am new i miss some understanding about doctrine 2 way of design)
Example:
<?php
// entities/User.php
/**
* #Entity #Table(name="users")
**/
class User
{
/**
* #Id #GeneratedValue #Column(type="integer")
* #var int
**/
protected $id;
/**
* #Column(type="string")
* #var string
**/
protected $name;
}
code example of use of build in validate(not need connect to db, only validate #Column(type="integer") ) basic function that not exist in doctrine 2:
$user=new User();
$user->setId('trtr');
$user->setName("goodname");
if($user->validate()){
echo 'ok';
}
else{
echo $user->validateError();
}
//output: id of User should be integer and not string
Thanks
Doctrine ORM assumes that entities you're persisting are in a valid state. That's the only job of the persistence layer, and adding validation to it would just be wrong. If you have entities with invalid data in them, you already have an invalid object graph that should not be saved.
So please keep in mind that if you ever had some API like
$someEntity->isValid();
Then something is probably wrong, since the entity should always be valid, and any dependencies of it should be set at construction time and handled in setters/getters so that the object never reaches an inconsistent state.
The main reason is separation of concerns. Since entities are fairly dumb objects that don't know much about the rest of the world, their ability to do validations is limited to begin with.
For instance, there's no way that your typical entity could validate that a particular property is unique.
That said, if you just want to do basic validations, just do them in the setters.
<?php
class MyEntity {
// ...
/**
* #ORM\Column(length="32")
*/
protected $myProperty;
public function setMyProperty($prop){
if (! is_string($prop))
throw new \InvalidArgumentException('MyEntity::setMyProperty() expects a string!';
if (strlen($prop) > 32)
throw new \LengthException('Argument passed to MyEntity::setMyProperty() is too long!');
$this->myProperty = $prop;
}
}
This approach can be used to enforce data types, lengths, etc. Anything beyond that is better handled somewhere other than inside your entity.
It's not good idea to mix entity and validation, but it make sense to have this rules in entity as annotation and validation logic in separated aspect validator class.
Check how it's done in Spring framework -
http://www.abtosoftware.com/blog/form-validation-using-aspect-oriented-programming-aop-in-spring-framework
and how to implement it with doctrine2 and go -
http://go.aopphp.com/blog/2013/07/21/implementing-logging-aspect-with-doctrine-annotations/

silverlight 4 with multiple domain service classes

In my SL Application I have multiple DomainService Classes which deals with the specific entities. Now I need to call upon a method from DomainService Class 1 in Class 2. How do I do that?
e.g
Product entity is handled in Class2 whereas the Workflow entities are handled by Class 1.
I have created a custom class which has properties from entities. Now I need to access the WorkflowStatus fields from one of Workflow entities for the relevant product in Class 2.
How can I call the Class1 method (GetLatestStatus(int productID)) from Class2's method GetProudctwithStatus()
public IList<ProductVS> GetProductsWithStatus()
{
var result = (from p in this.ObjectContext.Products
select new ProductVS
{
ProductID = p.ProductID,
Code = p.Code,
// ???
WFStatus = **Class1.GetLatestStatus(p.ProductID)**
}).ToList();
return result;
}
Any response would be much appreciated
If this is a common task I would instead create an operation on the Server which returned the data that you need. You can do this by creating the method and utilizing the [Invoke] attribute.
Otherwise you need to call two methods, both of which are asynchronous. If this was my project I would make the first call, then send a list of ProductID's to the server to retrieve the WorkFlow status. Otherwise you would be making N number of service calls to the server (one per each entity returned from the server) which is bad.