just curious .. I have some code like so:
//$em is EntityManager of Doctrine
//$className is a type that uses polymorphism (subtype of a parent type)
$pricing = $em->getRepository($className)->findOneBy(array(
'active' => true,
'product_id' => (int) $this->id
));
//gets serialization of certain variables of $className
return $pricing->getSerialization();
But ... instead of calling findOneBy outside of $className, can I move getSerialization() method inside the Entity (which is $className), and return class-parameters from there?
I imagine it is not possible, since Entity cannot read itself. Correct?
The problem I am trying to solve is. ... In the example above Entity is populated via Doctrine and then it returns data. Therefore I have to use another class to populate the entity. Without Doctrine I know it's possible to do things such as read data from inside the Entity i.e. via mysqli, and then return properties directly or via a method. In other words, do I absolutely need another location (class/function/method outside of Entity) to populate the entity?
Sample Entity looks like so
class Pricing
{
function getSerialization(){}
/**
* #var integer #Column(name="id", type="integer", nullable=false)
* #Id
* #GeneratedValue(strategy="IDENTITY")
*/
protected $id;
//etc, a typical Doctrine Entity
}
Yes, the instance of an entity class can read itself.
But I guess your question should have been: "Can a Doctrine entity load and read itself?". The answer to that is no...
Loading of entities is managed by doctrine internals. If you would want the entity classes to load themselves it would mean injecting an EntityManager into the entity class.
This is a bad idea, I quote #BryanM. his answer on another stackoverflow question that covers this nicely:
It is not a good idea to allow an entity object to rely on the entity manager. It ties the entity to the persistence layer, which was a problem Doctrine 2 was specifically trying to solve. The biggest hassle in relying on the entity manager is that it makes your model hard to test in isolation, away from the database.
You should probably be relying on service objects to handle the operations that rely on the entity manager.
It means you need to take care of loading entities externally. I still don't see the problem with getSerialization. It can be inside the Entity class and can be used after the entity is loaded right?
If you want to do loading and serializing at once I would suggest making a PricingService in which you inject the repository or entity manager and where you define a public methods that does all that. For example:
<?php
use Application\Entity\Pricing;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityRepository;
class PricingService
{
/**
* #var EntityManager
*/
protected $entityManager;
/**
* #param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
/**
* #return EntityRepository;
*/
protected function getRepository()
{
return $this->entityManager->getRepository(`Application\Entity\Pricing`);
}
/**
* #param $params
* #return array
*/
public function findSerializedBy($params)
{
$pricing = $this->getRepository()->findOneBy($params);
return $pricing->getSerialization();
}
}
Now you can work with your PricingService directly:
$serializedPricing = $pricingService->findSerializedBy(array(
'active' => true,
'product_id' => (int) $this->id
));
You can of course generalize your service by adding another parameter with the $classname.
Related
Let's say I have the following entities:
App\Entity\MainEntity:
/**
* #var object
*
* #ORM\OneToOne(targetEntity="App\Entity\DependentEntity", fetch="EAGER")
* #ORM\JoinColumn(name="DependentEntityType1FK", referencedColumnName="DependentEntityIDPK")
*/
private $dependentEntityType1;
/**
* #var object
*
* #ORM\OneToOne(targetEntity="App\Entity\DependentEntity", fetch="EAGER")
* #ORM\JoinColumn(name="DependentEntityType2FK", referencedColumnName="DependentEntityIDPK")
*/
private $dependentEntityType2;
Basically, one-directional 1:1 relationship from main entity to the same dependent entity using two different columns in the main entity table.
It doesn't matter, whether I use fetch="EAGER" or normal lazy loading through Doctrine proxy classes, when I do something like this:
$mainEntity = $this->mainEntityRepository->find(74);
$mainEntity->setDependentEntityType1($this->dependentEntityRepository->find(35));
$this->mainEntityRepository->saveTest($mainEntity);
where ::saveTest() is:
public function saveTest(MainEntity $mainEntity) {
$this->_em->persist($mainEntity->getDependentEntityType1());
$this->_em->merge($mainEntity);
$this->_em->flush();
}
it always tries to INSERT a new dependent entity to the table, even though I never made any changes (and even if I made them, it should have been UPDATE! for it)
The question is: why does Doctrine decide this dependent entity is a new one if I did $this->dependentEntityRepository->find(35) , so loaded an existing one?
I tried fetch="EAGER" thinking that spl_object_hash might return different hashes for a Proxy class instance and the actual DependantEntity one, but it doesn't matter, the DependantEntity is for some reason always considered as "new".
UPDATE: here is the code of ::setDependentEntityType1()
public function setDependentEntityType1(DependentEntity $dependentEntity) : void {
$this->dependentEntity = $dependentEntity;
}
I have 2 entities:
class Opponent
{
...
...
...
}
class Process
{
/**
* #var array
*
* #ORM\Column(name="answers_in_related_questionnaires", type="json", nullable=true)
*/
private $answersInRelatedQuestionnaires = [];
.
.
.
}
I have in the field answersInRelatedQuestionnaires amongst other things the object opponent
"opponent": {
"id":1088,
"name":"Inora Life Versicherung"
}
I want to write a getter in the entity process, that gets not only the both values id and name from opponent, but the whole entity Opponent. Something like this:
private function getOpponent() : Opponent
{
$id = $this->answersInRelatedQuestionnaires['opponent']['id'];
return $entityManager->getRepository(Opponent::class)->find($id)
}
I have read, that using of the entity manager within the entity is not a good idea. Which solutions for my issue are there? Can I use the Process repository in the Process entity?
You should not inject entity manager in an entity, it's a very bad practice and violates the separation of concerns between classes. BUT if you really want you indeed can inject entity manager in your entity.
GOOD PRACTICE:
Create a Model/Process class and include there any functionality that concerns your model. Doctrine entities are not model classes. In Model/Process you can inject the entity manager and any other service, you need.
EDIT: By creating a Model/Process class I mean creating a class named Process inside Model directory in your /src folder. Your path of your class will be: /src/Model/Process. Of course, the name of the directory or the class can by anything, but this is a typical convention. Your Model class should be responsible for all your business logic, such as validation of your model etc. This will indeed make your code structure more complicated but will be a savor in the long run for large scale projects. You will also need a Model/ProcessManager to properly populate Process model in different cases (e.g. when loaded from Database, user form etc.) Of course, in the end it's all a matter of trade-off between complexity and sustainability.
An interesting approach about models in Symfony, mostly applicable in large scale projects, can be found here.
ALTERNATIVES:
If you access the opponent attribute only after an entity has been loaded you can use Doctrine PostLoad LifecycleCallback to properly set opponent attribute. This is not a bad practice:
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
/**
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks()
*/
class Product
{
// ...
private $opponentObject;
/**
* #ORM\PostLoad
*/
public function onPostLoad(LifecycleEventArgs $args){
$em = $args->getEntityManager();
$id = $this->answersInRelatedQuestionnaires['opponent']['id'];
$this->opponentObject = $em->getRepository(Opponent::class)->find($id);
}
public function getOpponent() {
return $this->opponent;
}
}
Finally if you really really want to inject the entity manager into your entity you can achieve that with dependency injection via autowiring:
use Doctrine\ORM\EntityManagerInterface;
class Process
{
private $em;
public function __contruct(EntityManagerInterface $em)
{
$this->em = $em;
}
....
}
I have Entities and Repositories in my project. To simplify, I have
EntityInterface
UserEntity
BusinessEntity
Interface:
interface Entity
{
/**
* #return EntityId
*/
public function getId();
}
Implementations
class UserEntity implements Entity
{
/**
* #return EntityId
*/
public function getId(){
//...do something here for return
return $userId;
}
}
and
class BusinessEntity implements Entity
{
/**
* #return EntityId
*/
public function getId(){
//...do something here for return
return $userId;
}
}
I would like to define a Repository base-functionality, like save, so my interface looks like:
interface Repository
{
/**
* #param Entity $entity
*
* #throws \InvalidArgumentException If argument is not match for the repository.
* #throws UnableToSaveException If repository can't save the Entity.
*
* #return Entity The saved entity
*/
public function save(Entity $entity);
}
Later, I have different interfaces for different type of Repositories, like UserRepository and BusinessRepository
interface BusinessRepository extends Repository
{
/**
* #param BusinessEntity $entity
*
* #throws \InvalidArgumentException If argument is not match for the repository.
* #throws UnableToSaveException If repository can't save the Entity.
*
* #return Entity The saved entity
*/
public function save(BusinessEntity $entity);
}
The above code fails, because Declaration must be compatible with Repository...
however BusinessEntity implements Entity, so it's compatible.
I have many type of entities, so If I can't type-hint, I always need to check, that the passed instance is instanceof what I need. It's stupid.
The following code fails again:
class BusinessRepository implements Repository
{
public function save(BusinessEntity $entity)
{
//this will fail, however BusinessEntity is an Entity
}
}
In general, method parameters have to be contravariant with respect to an inheritance hierarchy or invariant. This means that indeed BusinessEntity would not be "compatible" with Entity when used as a type for a method parameter.
Think of it from a "contract" point of view. Your interface Repository promises that its method save can handle arguments of type Entity. Subtypes inheriting from Repository should be bound to this introduced contract (because otherwise, what sense would it make to define types in the first place, if you cannot be sure what they promises to be able to do?).
Now, if a subtype all of a sudden only accepts more special types, like BusinessEntity, but no longer Entity, the contract's broken. You cannot use BusinessRepository as Repository any more, because you cannot call save with an Entity.
This is counterintuitive at first, but have a look at this: https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)#Contravariant_method_argument_type
Notice the inheritance arrow in the image.
What's to do? Get rid of the idea of inheritance being the holy grail in object oriented programming. Most of the time, it is not, and introduces all kinds of nasty coupling. Favor composition over inheritance, for example. Have a look at Parameter type covariance in specializations.
It fails because you declare methods that takes different arguments in interfaces. There is also question if there is any different logic in saving BusinessEntity than Entity. I think it shouldn't be. So you can omit save function in business entity and save just work on Entity and should know that Entity has "save" method.
The other way is to use factory pattern or abstract factory over inheritance.
I need to cache some info about a user who is logged in (such as security groups, name, username, etc.)
Currently I have a separate class to achieve just this, lets call it CurrentUserHelper. Given a user object, it will cache the appropriate data and save store info in the $_SESSION variable.
The issue is I'm finding a bunch of classes relying just on CurrentUserHelper because they only need a couple of common fields. In fact, most of the functions have the same name as my User class. There's a couple of functions in CurrentUserHelper, such as getSecurityGroupsNames(), that contains a cache of all security group names, but there is no reason this function name could not be in the user class also.
Instead, should I create a CachedUser class and pass this around? This class can extend User, but then I can override getName(), getSecurityGroups(), etc, and returned the cached data, and not preform db requests to get the data.
The downside of passing around a CachedUser object is that this kind of hides the fact the data isn't really up to date if a constructor/function is accepting a type User. I also need to find way to handle merging the entity with Doctrine 2, and making sure entities associating themselves with a CachedUser won't break. If I decide to cache some temporary data (such as # of page views since logged in), this property shouldn't be part of the User class, it's more about the current user's session.
If I continue using the CurrentUserHelper class, maybe I should create an interface and have both CurrentUserHelper and User for the common functionality the two classes would share?
Preface: Extension isn't the best way for these sorts of things.. I'm sure you've heard composition over inheritance shouted at you over and over again. In fact, you can even gain inheritance without using extends!
This sounds like a good use-case for the decorator pattern. Basically, you wrap your existing object with another one that implements the same interface, so it has the same methods as the inner object, but this object's method adds the extra stuff around the method call to the inner object, like caching, for example.
Imagine you have a UserRepository:
/**
* Represents an object capable of providing a user from persistence
*/
interface UserProvider
{
/**
* #param int $id
*
* #return User
*/
public function findUser($id);
}
/**
* Our object that already does the stuff we want to do, without caching
*/
class UserRepository implements UserProvider
{
/**
* #var DbAbstraction
*/
protected $db;
/**
* #var UserMapper
*/
protected $mapper;
/**
* #param DbAbstraction $db
* #param UserMapper $mapper
*/
public function __construct(DbAbstraction $db, UserMapper $mapper)
{
$this->db = $db;
$this->mapper = $mapper;
}
/**
* {#inheritDoc}
*/
public function findUser($id)
{
$data = $this->db->find(['id' => $id]);
/** Data mapper pattern - map data to the User object **/
$user = $this->mapper->map($data);
return $user;
}
}
The above is a really simple example. It'll retrieve the user data from it's persistence (a database, filesystem, whatever), map that data to an actual User object, then return it.
Great, so now we want to add caching. Where should we do this, within the UserRepository? No, because it's not the responsibility of the repository to perform caching, even if you Dependency Inject a caching object (or even a logger!).. this is where the decorator pattern would come in useful.
/**
* Decorates the UserRepository to provide caching
*/
class CachedUserRepository implements UserProvider
{
/**
* #var UserRepository
*/
protected $repo;
/**
* #var CachingImpl
*/
protected $cache;
/**
* #param UserRepository $repo
*/
public function __construct(UserRepository $repo, CachingImpl $cache)
{
$this->repo = $repo;
$this->cache = $cache;
}
/**
* {#inheritDoc}
*
* So, because this class also implements UserProvider, it has to
* have the same method in the interface. We FORWARD the call to
* the ACTUAL user provider, but put caching AROUND it...
*/
public function findUser($id)
{
/** Has this been cached? **/
if ($this->cache->hasKey($id))
{
/**
* Returns your user object, or maps data or whatever
*/
return $this->cache->get($id);
}
/** Hasn't been cached, forward the call to our user repository **/
$user = $this->repo->findUser($id);
/** Store the user in the cache for next time **/
$this->cache->add($id, $user);
return $user;
}
}
Very simply, we've wrapped the original object and method call with some additional caching functionality. The cool thing about this is that, not only can you switch out this cached version for the non-cached version at any time (because they both rely on the same interface), but you can remove the caching completely as a result, just by changing how you instantiate this object (you could take a look at the factory pattern for that, and even decide which factory (abstract factory?) depending on a configuration variable).
i'm trying to implement the RowGateway class to my entities, I already have a form working with the entity and I'm trying to set the hydrator to work with ClassMethods.
I also noticed that ArraySerializable hydrator calls the populate() method or exchangeArray() and this method set the appropriate primary key when editing a row, unfortunately ClassMethods Hydrator doesn't do that.
What would be the best way to set the correct primary key value when using the Classmethod hydrator, should I set this value before binding the entity to the form? Or, should I extend the Classmethod H. to perform this task on initialize?
I'm not fond of using knowledge of the data layer in my entity. When using exchangeArray() you create mapping in the entity itself. I did some research about Zend's hydrators and came across serval posts including this one. Andrew's example of extending the ClassMethods hydrator seemed a good approach to map column names to getters/setters names.
When extending the ClassMethods hydrator you could also implement Zend\Stdlib\Hydrator\HydratorInterface.
For data manipulation use hydrator strategies.
http://framework.zend.com/manual/2.0/en/modules/zend.stdlib.hydrator.strategy.html
http://juriansluiman.nl/nl/article/125/strategies-for-hydrators-a-practical-use-case
To sepperate your entity over mutliple data sources you can use hydrator filters. For example, by default the ClassMethods hydrator extracts all entity methods starting with get.
http://framework.zend.com/manual/2.1/en/modules/zend.stdlib.hydrator.filter.html
You could extend Zend\Stdlib\Hydrator\ClassMethods and do any transformations you require here, assuming this is what you mean.
You can then use mapField to map from one of your fields to the correct id field name.
namespace Application\Model;
use Zend\Stdlib\Hydrator\ClassMethods;
class MyHydrator extends ClassMethods
{
/**
* Extract values from an object
*
* #param object $object
* #return array
* #throws Exception\InvalidArgumentException
*/
public function extract($object)
{
$data = parent::extract($object);
$data = $this->mapField('id', 'user_id', $data);
return $data;
}
/**
* Map fields
*
* #param type $keyFrom
* #param type $keyTo
* #param array $array
* #return array
*/
protected function mapField($keyFrom, $keyTo, array $array)
{
$array[$keyTo] = $array[$keyFrom];
unset($array[$keyFrom]);
return $array;
}
}
Alternatively you could make a getter and setter for the id field you need setting/getting, for example if you have an id called 'user_id' :
public function getUserId() { .. }
public function setUserId($id) { .. }