I am in need of grabbing a few fields of an entity, running them through some processing, and returning the processed data. I am wondering if it is possible to call the getters of the Entity for which the custom repository is being built inside that custom repository? The only way I thought of so far seems like it would create an infinite loop by calling the entity's repository, which would include a call to the very custom repository being used as well.
I can write the actual queries, but I figured it it would be cleaner to access the data through existing methods, then why not?
Update: So I built a method in the custom repository that I pass the entity object to that I want to work with. Seems a little weird that I would have to pass the entity to it's own custom repository so that it would know what to act on, but I can't seem to find any other way. So in my Controller right now I am calling the entity, then calling up the repository for the entity, and passing the previously called entity to the repository. Is that right?
$user = $this->get('security.context')->getToken()->getUser();
$user_repository = $this->getDoctrine()->getRepository('AppBundle:User');
$profiles = $user_repository->getAllUsersProfiles($user);
It turns out I had the whole concept of Custom Repositories incorrect. I was using them to store methods that would pull out data relevant to the entity, but only relevant in the sense that the entity was being used to filter something else.
Prior to this epiphany my User Custom Repository had methods like getAllUsersProfiles($user) and getAllUsersCampaigns($user). My previously incorrect understanding was that because the User entity was the thing that was central to filtering the Profiles and Campaigns, that these belonged in the User Custom Repository.
What I have now come to understand is that getAllUserProfiles($user) belongs in the Profiles Custom Repository, and would be more appropriately named getAllByUser($user). Now when I need to use it, I pull up the Profiles Repository and call the appropriate method:
$profile_repository = $this->getDoctrine()->getRepository('AppBundle:Profile');
$all_profiles = $profile_repository->getAllByUser($user);
Related
For an blog entry entity I am loading data from an api via the doctrine postloadEvent. For this i created a listener service with an postloadMethod in it.
public function postLoad(BlogEntry $blogEntry)
{
$blogentry->setName($apiClient->getName($blogEntry->getId()))
$blogentry->setContent($apiClient->getContent($blogEntry->getId()))
...
}
This means, there is already a local repository with blog entries. These blogentries are connected to a blog. If i now only want to count the blogentries for each blog, i would implement a getBlogEntryCount() method on the BlogEntry entity and call it.
$blog->getBlogEntryCount();
The problem now is, that the postLoad event is triggered unnecessary, even if i need no data from the api.
How can i avoid this behaviour in doctrine/symfony/sonata admin? Is there mechanism like "lazy loading" for doctrine entities?
Update to Jose M. González Solution
To get only the count of the collection, the extra_lazy loading solution will do it.
For getting local information without triggering the api call i used the said repository function. To get this information working in list view in sonata admin, i created a non-doctrine-related array field "blogEntriesSimple" in my Blog Entity next to my "blogEntries" (which is normally holding the complete entity) field.
I attached an entitylistener with postLoad function to the Blog Entity, which is filling up my blogEntriesSimple array with the information from my custom repository function.
Thats it.
I think this solution is a bit hacky, but until no cleaner solution is available, this will do it.
i think that you can achieve this with the extra lazy associations that permit that you count your related entities without hydrating it
Edited
Also you can do a DQL query that only hidrate a partial view of your entity and it can be used to count the rows and access to your properties, for example:
select be.id,be.title from AppBundle\Entity\BlogEntry be
This query must not trigger the postLoad event
I hope this can help you
I have some personal data structure mixed with "standard fields". I would like to avoid the manual work on simple fields (with datastore native API):
toPersist.setProperty("field1", value1);
toPersist.setUnindexedProperty("field2", value2);
but I still want to get the prefilled Entity instance toPersist so I can add my own #Ignore fields my self
For example:
Entity filled = OfyService.ofy().save().entity(this).fill();
filled.setProperty("mySpecialField", jsonValue);
//...
// I want to save my entities alone
datastore.put( filled );
reversely I'd like to get the Entity object representing each entry in a load() call.
Is this possible? or do I have to dive into Objectify code to hack it?
thanks for your answers
I don't follow your question exactly, but I'm pretty sure what you're looking for are the #OnLoad and #OnSave annotations. You add them to methods within your entity classes, and those methods will be called just after an entity is loaded, or just before one is saved, respectively. The documentation for them is here.
Edit:
After your comments (below) I now understand what you are trying to accomplish. Yes, Objectify supports this (though I have never tried it myself). You want to use the Saver.toEntity() and Loader.fromEntity() methods. It appears you can use them like this:
// Use Objectify to convert a POJO into an Entity
Entity filled = ofy().save().toEntity(myPojo);
// Use Objectify to convert an Entity into a POJO
Object pojoCopy = ofy().load().fromEntity(filled);
I would like to return the page Entity from the method: getByPath($path). I just would like to know where this method should be in the script. Inside the controller or inside the entity class?
In my opinion the entity "Page" shouldn't have a function called "getByPath()" since an entity should only contain database information of one entity, which can be get or set by getters and setters. And this "getByPath" function is not just a getter or setter it requires me to run the entitymanager within the entity. Am I right?
So am I right that I should make a PageController and create the "getByPath()" (which will return the page object) function there? Or would anyone create that function inside the entity class?
I would like to know what the nicest way is to accomplish this.
Thanks in advance.
You should put that function inside a custom repository for the Page entity
While the Entities are the objects you are storing, the Repository is the class that provides methods to access/load those objects, eg when you call $em->getRepository('Entities\Page')->find($page_id);, you call the find() method on your Page repository and it's its job to find it for you.
Doctrine provides a default repository for each entity (with the various find*() methods, ...), but you can provide a custom one where you can add your own method, such as getByPath().
Symfony 2 - Database and Doctrine - Custom Repository Classes
Doctrine 2 - Custom repository
I'm using Symfony2 with Doctrine2. I want to achieve the following:
$place = $this->getDoctrine()->getRepository('TETestBundle:Place')->find($id);
And on that place will be the info of the place (common data + texts) on the user language (in session). As I am going to do that hundreds of times, I want to pass it behind the scenes, not as a second parameter. So an English user will view the place info in English and a Spanish user in Spanish.
One possibility is to access the locale of the app from an EntityRepository. I know it's done with services and DI but I can't figure it out!
// PlaceRepository
class PlaceRepository extends EntityRepository
{
public function find($id)
{
// get locale somehow
$locale = $this->get('session')->getLocale();
// do a query with the locale in session
return $this->_em->createQuery(...);
}
}
How would you do it? Could you explain with a bit of detail the steps and new classes I have to create & extend? I plan on releasing this Translation Bundle once it's ready :)
Thanks!
I don't believe that Doctrine is a good approach for accessing session data. There's just too much overhead in the ORM to just pull session data.
Check out the Symfony 2 Cookbook for configuration of PDO-backed sessions.
Rather than setting up a service, I'd consider an approach that used a Doctrine event listener. Just before each lookup, the listener would pick out the correct locale from somewhere (session, config, or any other place you like in the future), inject it into the query, and like magic, your model doesn't have to know those details. Keeps your model's scope clean.
You don't want your model or Repository crossing over into the sessions directly. What if you decide in the future that you want a command-line tool with that Repository? With all that session cruft in there, you'll have a mess.
Doctrine event listeners are magically delicious. They take some experimentation, but they wind up being a very configurable, out-of-the-way solution to this kind of query manipulation.
UPDATE: It looks like what you'd benefit from most is the Doctrine Translatable Extension. It has done all the work for you in terms of registering listeners, providing hooks for how to pass in the appropriate locale (from wherever you're keeping it), and so on. I've used the Gedmo extensions myself (though not this particular one), and have found them all to be of high quality.
I have a value stored in my parameters.ini file, and I need to access it during the prepersist method of my model.
Normally I use $this->container->getParameter('value');, but the container is not available in the entity.
Is there a way to get parameters within an entity class?
P.S. The value is an API key for a service I am pulling info from during prepersist. Best practice is to keep keys/passwords in parameters.ini
Best practice is to use a service to persist your entity. This one would inject the container and set your parameter when you call your updateMyEntity() service method.
Inside your controller (or whatever you want):
$user = new User('foo');
$user->setSomeProperty('bar');
$userService->update($user);
Inside the UserService:
public function update(User $user) {
$user->setSomeParameter($this->container->getParameter('value'));
$this->em->persist($user);
}
In addition to Florent's answer, Entities are meant to be purely data objects. They should not know about any other variables or services within your application. I'm more curious about why your entity needs to know anything about an API key that is system-wide. With very little background information, I'd say you should rethink what you are trying to do.
You need a service to interact with the API, ideally configured through the container. I don't see what that has to do with an entity.