可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'd like to use, something like:
$em = $this->getEntityManager();
Inside a Entity.
I understand I should do this as a service but for some testing purposes, I want to access it from an Entity.
Is it possible to achieve that?
I've tried to:
$em = $this->getEntityManager();
$profile_avatar = $em->getRepository('bundle:Perfils')->findOneByUser($this-getId());
But isn't working.
Fatal error: Call to undefined method
Proxies\webBundleEntityUserProxy::getEntityManager() in
/opt/lampp/htdocs/web/src/Pct/bundle/Entity/User.php on line
449
Why am I trying to do it this way?
I've 3 kinds of users: Facebook, Twitter and MyOwnWebsite users. Each of them have differents avatar which links facebook's profile, twitter's or otherwise, if its myownwebsite user, I retrieve the avatar from a URL in a database. For now, I don't want to create a service, because I'm just trying to make it working, to test it, not to create a final deployment. So this is why I'm trying to call Entity manager from an Entity. I don't want, by now, to modify configuration files, just this entity.
回答1:
As pointed out (again) by a commenter, an entity manager inside an entity is a code smell. For the OP's specific situation where he wished to acquire the entity manager, with the least bother, a simple setter injection would be most reliable (contrary to my original example injecting via constructor).
For anyone else ending up here looking for a superior solution to the same problem, there are 2 ways to achieve this:
Implementing the ObjectManagerAware
interface as suggested by https://stackoverflow.com/a/24766285/1349295
use Doctrine\Common\Persistence\ObjectManagerAware;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Entity implements ObjectManagerAware
{
public function injectObjectManager(
ObjectManager $objectManager,
ClassMetadata $classMetadata
) {
$this->em = $objectManager;
}
}
Or, using the @postLoad
/@postPersist
life cycle callbacks and acquiring the entity manager using the LifecycleEventArgs
argument as suggested by https://stackoverflow.com/a/23793897/1349295
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\HasLifecycleCallbacks()
*/
class Entity
{
/**
* @ORM\PostLoad
* @ORM\PostPersist
*/
public function fetchEntityManager(LifecycleEventArgs $args)
{
$this->setEntityManager($args->getEntityManager());
}
}
Original answer
Using an EntityManager
from within an Entity
is VERY BAD PRACTICE. Doing so defeats the purpose of decoupling query and persist operations from the entity itself.
But, if you really, really, really need an entity manager in an entity and cannot do otherwise then inject it into the entity.
class Entity
{
private $em;
public function __contruct($em)
{
$this->em = $em;
}
}
Then invoke as new Entity($em)
.
回答2:
Best way is to use Life Cycle: @ORM\HasLifecycleCallbacks
And you can use the appropriate Event as you want to get result:
@postLoad
@postPersist
...
回答3:
Calling the Entity Manager from inside an Entity is a bad practice! You should keep your entities as simple as possible.
For what purpose do you need to call the Entity Manager from an Entity?
回答4:
What I think you should do is, instead of using the Entity Manager inside your entity, is to create a custom repository for your entity.
In your entity ORM file, add an entry as follows (or in your entity class annotations if not using YML):
App\Bundle\Profils:
# Replace the above as appropiate
type: entity
table: (your table)
....
repositoryClass: App\Bundle\CustomRepos\ProfilsRepository
# Replace the above as appropiate.
# I always put my custom repos in a common folder,
# such as CustomRepos
Now, create a new PHP class that has the namespace above:
//Your ProfilsRepository.php
<?php
namespace App\Bundle\CustomRepos;
use Doctrine\ORM\EntityRepository;
class ProfilsRepository extends EntityRepository
{
/**
* Will return the user url avatar given the user ID
* @param integer $userID The user id.
@return string The avatar url
*/
public function getUserProfile($userId)
{
$em = $this->getEntityManager();
$qb = $em->createQueryBuilder();
$qb->select... (your logic to retrieve the profil object);
$query = $qb->getQuery();
$result = $query->getResult();
return $result;
}
}
Finally, in your Controller:
// Your controller
<?php
namespace <class namespace>;
...
use App\Bundle\CustomRepos\ProfilsRepository;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
...
class YourClassNameController extends Controller
{
public function yourAction()
{
$userId = <get the user ID>;
// Pass the name of your entity manager to the
// getManager function if you have more than one and
// didn't define any default
$em = $this->getDoctrine()->getManager();
$repo = $em->getRepository('Profils');
$avatar = $repo->getUserProfile($userId);
...
}
}
回答5:
You need to set the services.yml with:
services:
your_service_name:
class: AppBundle\Controller\ServiceController
arguments: [ @doctrine.orm.entity_manager ]
You need to set also the Controller with the following constructor:
public function __construct(\Doctrine\ORM\EntityManager $em)
{
$this->em = $em;
}
and use $this->em
in the controller
(for example $connection = $this->em->getConnection();
)