JMSSerializer comes with a Doctrine Object Constructor that does its job, but imagine an Entity with two properties forming a primary key:
UserBase
prop annotated with #ORM\Id and #Serializer\Groups({"1"})
- username
prop annotated with #ORM\Id and #Serializer\Groups({"2"})
- email
User extends UserBase
- other props here, no Id defined.
one property key is excluded by using group=1 while deserializing. The client potentially still sends both email and username. email should not be considered though.
Unfortunately, if you pass the two properties in the body, DoctrineObjectConstructor does not check if something is excluded by deserialization, so it tries to load the Entity from the DB, according to the two values:
foreach ($classMetadata->getIdentifierFieldNames() as $name) {
if ( ! array_key_exists($name, $data)) {
return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
}
$identifierList[$name] = $data[$name];
}
What I would like to do is taking into account my annotated groups, so as to use the fallbackConstructor in case some property forming the identifier is missing.
As a starter this is a good point: I created my own service, by passing along the annotationDriver. Then, if the property forming the identifier is not associated with the actual group:
$classMetadata = $this->annotationDriver->loadMetadataForClass($metadata->reflection);
$classMetadata->properties //here groups are listed for each property
I can fall back to the fallbackConstructor, as if I had not passed that property in the body
...not so fast! My Entity User extends a UserBase where all my identifier are, so I should take into account hierarchy, possibly in a generic way.
Any hint?
Alright, JMSSerializer's Object Constructor does not consider serialization groups when determing identifiers. Hence, if you include all the IDs in your object, whether they are part of the actual context group or not, they will be counted in.
I created an alternative version of the Object in order to fix this misbehavior (at least for me). Hope it helps
Related
I have foo an instance of the ember-data model thing. thing.js has the following property :
owner: DS.belongsTo('user')
If I have foo with an empty owner, how can I, with only foo and the 'owner' string, retrieve the value 'user' representing the model of the owner relation?
EDIT: I want to allow my select-relation component to works with relations where the name is different from the class name
It sounds like you have some work to do to finish setting up your relationships. Have a read through this page of the guides.
If the relationships are set up correctly, to get the associated user, you should be able to do foo.owner. This assumes that users are already present in the store. I recommend using the Ember Inspector browser plugin to debug the relationships.
This looks like a use case for typeForRelationship.
In your example you should be able to do something like
store.modelFor('thing').typeForRelationship('owner', store);
If you don't like that approach you can use the belongsTo reference API, where you use the meta data from the relationship to get the type
foo.belongsTo('owner').type
The only thing with that approach is that the type property may not be public API and possible (though unlikely) to change at some point.
It seems I can do the following :
this.get('model').get('_internalModel._relationships.initializedRelationships.'+this.get('relation')+'.relationshipMeta.type')
model being an instance and relation the string of the relation name, it correctly return the model of the relation.
EDIT : a better solution not using private API courtesy from the ember discord :
function getRelatedModelName(record, relationName){
let ParentModelClass = record.constructor;
let meta = get(ParentModelClass, 'relationshipsByName').get(relationName);
return meta.type;
}
I have problem with update entity with relations (one to many, many to one). I trying to add some new element to ArrayCollection when update, but nothing to do.
Here is my code of create and add relation:
$auctionPhoto = new AuctionPhoto();
$auctionPhoto->setAuction($auction);
$auctionPhoto->setPath($path);
$auction->getPhotos()->add($auctionPhoto);
All is running by doctrine entity listener (preUptade). The same code is do when I create entity (prePersist), but then is works fine.
I debug this and before persist I have in Auction object right relations, but nothing save to database.
Why do you do $auction->getPhotos()->add($auctionPhoto) ?
You should have a method addPhoto() or addAuctionPhoto() in your Auction entity, and use it like this:
$auction->addPhoto($auctionPhoto) or $auction->addAuctionPhoto($auctionPhoto)
EDIT:
Maybe your entity Auction is not the owner of the relation between the two entities, then you need to add $auctionPhoto->setAuction($auction), or if it's ManyToMany relation, then add $auctionPhoto->addAuction($auction)
Replace $auction->getPhotos()->add($auctionPhoto); with $auction->addPhoto($auctionPhoto);.
In your Auction entity, define the new method
// Auction.php
public function addPhoto(AuctionPhoto $thePhoto)
{
$this->photos[] = $thePhoto; // Add the photo to the object
$thePhoto->setAuction($this); // AuctionPhoto entity need to know about the reference
return $this; // Just for method chaining
}
(I assume $photos is your ArrayCollection which contains auction's photos)
Basically what you missed is to give a reference back to your entity:
$thePhoto->setAuction($this);
Are you saying nothing is in the database before you run this:
$em->persist($auction);
$em->flush();
If so, that is correct functionality. You need to persist then flush, then data is stored.
I am facing trouble using doctrine join. I can't share my code. But I can tell you scenario.
Please help me to achieve that.
I have created 2 entity. One User and Language.
User table is having foreign key language_id. and Language is master table with id and code fields.
I want to fetch user with some criteria, such a way it returns Language code from Language table as well.
I write join for that but it returns some full object...
Not sure how to fetch corresponding language code from Language table for language_id set in user table
If there is some example you know which can help me then also fine
i have return this in __construct()
$this->languageObj = new ArrayCollection();
when we print it is gives this
[languageObj:User:private] => Common\User\Entity\Language Object
(
[languageId:Language:private] => 1
[languageCode:Language:private] => en
[languageName:Language:private] => English
[languageCode2:Language:private] => User Object
RECURSION
)
I am not able to fetch languageCode from the object
You need methods defined in your entity to return the value from the object. It seems like everything is correct you would just need to grab the value from the entity. Here is an example:
$userEntity->getLanguageObj()->getLanguageId();
Your user Entity would need the getLanguageObj method which you can define like this:
public function getLanguageObj() {
return $this->languageObj;
}
And your Language Entity would also need a getLanguageId method:
public function getLanguageId() {
return $this->languageId;
}
Hope that helps!
I'm exploring the possibility of using MVC for my next e-commerce site. One thing I can't seem to figure out is whether or not I can use the same URL convention I normally use. Currently, the URL for any product could be one of the following:
Category/SubCategory/Product1.html
Category/SubCategory/SubSubCategory/Product2.html
Category/SubCategory/SubSubCategory/Product3.html
Category/SubCategory/SubSubCategory/SubSubSubCategory/Product4.html
etc.
The issue I'm having is with the nested category structure. So far the only thing I've come up with is as follows:
routes.MapRoute(
"Products",
"{categories}/{productname}",
new { controller = "Product", action = "Details", productname = UrlParameter.Optional },
new { categories = #"\w+/\w+" }
);
I was hoping that {categories} could be matched with any one of the following which I could process to identify the right category that the product belongs to:
Sport/Tennis/Rackets/ProductA
Sport/Badminton/Rackets/ProductB
But the route shown above doesn't work correctly.
Does anyone know how this can be achieved, or if it can't be done?
The routing system allows you to define catchall parameters, which ignore slashes and capture
everything up to the end of a URL. Designate a parameter as being catchall by prefixing it with an
asterisk (*).
routes.MapRoute(null, "Articles/{*articlePath}",
new { controller = "Articles", action = "Show" }
);
You can only have one catchall parameter in a URL pattern, and it must be the last (i.e.,
rightmost) thing in the URL, since it captures the entire URL path from that point onward.
One Caveat though, it doesn’t capture anything from the query string as route objects only look at the
path portion of a URL.
Catchall parameters are useful if you’re letting visitors navigate through some kind of arbitrary
depth hierarchy, such as in a content management system (CMS).
You can use the RouteData object to extract information about the route. For your needs, you would probably create a custom route handler that parses the route data and calls the correct controller methods.
You need access to the individual segments of the URL so you need to divide the category segment into two segments. That would make it much easier.
Let's say we call Tennis and Badminton categories and Rackets within those categories as a product class
You need a way to access the category, productClass and productName parameters. Supposing that "Sport" is fixed in this case, I will do it like this:
routes.MapRoute(
"Products",
"sport/{category}/{productClass}/{productName}",
new { controller = "Product", action = "Details", productClass = UrlParameter.Optional, productName = UrlParameter.Optional }
);
Your action method will be something like this
public ActionResult Details(string category, string productClass, string productName){
//Do whatever you need to do in order to get the specified product
}
You could use Areas in MVC2
So it would read:
Area/Controller/View/id
So in your case it would end up being:
Sport being the area,
Tennis The controller,
Rackets the view,
ProductA being an ID or querystring,
http://www.asp.net/mvc/videos/aspnet-mvc-2-areas
Hope this makes sense.
Update 3 (Read This First) :
Yes, this was caused by the object "profile" not having been saved. For those getting the same symptoms, the moral is "If a ForeignKey field seems to be getting set to None when you assign a real object to it, it's probably because that other objects hasn't been saved."
Even if you are 100% sure that it was saved, check again ;-)
Hi,
I'm using content_type / generic foreign keys in a class in Django.
The line to create an instance of the class is roughly this :
tag = SecurityTag(name='name',agent=an_agent,resource=a_resource,interface=an_interface)
Where both agent and resource are content_type fields.
Most of the time, this works as I expect and creates the appropriate object. But I have one specific case where I call this line to create a SecurityTag but the value of the agent field seems to end up as None.
Now, in this particular case, I test, in the preceding line, that the value of an_agent does contain an existing, saved Django.model object of an agent type. And it does.
Nevertheless, the resulting SecurityTag record comes out with None for this field.
I'm quite baffled by this. I'm guessing that somewhere along the line, something is failing in the ORM's attempt to extract the id of the object in an_agent, but there's no error message nor exception being raised. I've checked that the an_agent object is saved and has a value in its id field.
Anyone seen something like this? Or have any ideas?
====
Update : 10 days later exactly the same bug has come to bite me again in a new context :
Here's some code which describes the "security tag" object, which is basically a mapping between
a) some kind of permission-role (known as "agent" in our system) which is a generic content_type,
b) a resource, which is also a generic content_type, (and in the current problem is being given a Pinax "Profile"),
and c) an "interface" (which is basically a type of access ... eg. "Viewable" or "Editable" that is just a string)
class SecurityTag(models.Model) :
name = models.CharField(max_length='50')
agent_content_type = models.ForeignKey(ContentType,related_name='security_tag_agent')
agent_object_id = models.PositiveIntegerField()
agent = generic.GenericForeignKey('agent_content_type', 'agent_object_id')
interface = models.CharField(max_length='50')
resource_content_type = models.ForeignKey(ContentType,related_name='security_tag_resource')
resource_object_id = models.PositiveIntegerField()
resource = generic.GenericForeignKey('resource_content_type', 'resource_object_id')
At a particular moment later, I do this :
print "before %s, %s" % (self.resource,self.agent)
t = SecurityTag(name=self.tag_name,agent=self.agent,resource=self.resource,interface=self.interface_id)
print "after %s, %s, %s, %s" % (t.resource,t.resource_content_type,type(t.resource),t.resource_object_id)
The result of which is that before, the "resource" variable does reference a Profile, but after ...
before phil, TgGroup object
after None, profile, <type 'NoneType'>, None
In other words, while the value of t.resource_content_type has been set to "profile", everything else is None. In my previous encounter with this problem, I "solved" it by reloading the thing I was trying to assign to the generic type. I'm starting to wonder if this is some kind of ORM cache issue ... is the variable "self.resource" holding some kind proxy object rather than the real thing?
One possibility is that the profile hasn't been saved. However, this code is being called as the result of an after_save signal for profile. (It's setting up default permissions), so could it be that the profile save hasn't been committed or something?
Update 2 : following Matthew's suggestion below, I added
print self.resource._get_pk_value() and self.resource.id
which has blown up saying Profile doesn't have _get_pk_value()
So here's what I noticed passing through the Django code: when you create a new instance of a model object via a constructor, a pre-init function called (via signals) for any generic object references.
Rather than directly storing the object you pass in, it stores the type and the primary key.
If your object is persisted and has an ID, this works fine, because when you get the field at a later date, it retrieves it from the database.
However -- if your object doesn't have an ID, the fetch code returns nothing, and the getter returns None!
You can see the code in django.contrib.contenttypes.generic.GenericForeignKey, in the instance_pre_init and __get__ functions.
This doesn't really answer my question or satisfy my curiosity but it does seem to work if I pull the an_agent object out of the database immediately before trying to use it in the SecurityTag constructor.
Previously I was passing a copy that had been made earlier with get_or_create. Did this old instance somehow go out of date or scope?