I'm writing a functional test for an Action
entity having a relationship with the User
entity:
<?php
namespace Acme\AppBundle\Entity;
/**
* Class Action
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="Acme\AppBundle\Repository\ActionRepository")
*/
class Action
{
/**
* @var int
*
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var \Acme\AppBundle\Entity\User
*
* @ORM\ManyToOne(targetEntity="\Acme\AppBundle\Entity\User", inversedBy="actions")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $createdBy;
}
User:
namespace Acme\AppBundle\Entity;
/**
* @ORM\Entity
* @ORM\Table(name="`user`")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="Action", mappedBy="createdBy")
*/
private $actions;
}
And the user is setted in the controller with the following snippet:
<?php
namespace Acme\ApiBundle\Controller;
/**
*
* @Route("/actions")
*/
class ActionController extends FOSRestController
{
public function postAction(Request $request)
{
$action = new Action();
$action->setCreatedBy($this->getUser());
return $this->processForm($action, $request->request->all(), Request::METHOD_POST);
}
}
When calling the action with a REST client for example, everything works fine, the relationship between Action
and User
is persisted correctly.
Now, when testing the action with a functional test, the relationship is not working because of the following error:
A new entity was found through the relationship 'Acme\AppBundle\Entity\Action#createdBy' that was not configured to cascade persist operations for entity: test. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}).
For my functional test I need to inject a JWT and a session token because my routes are secured by a JWT and I need to have a user in session.
Here is how I inject that:
<?php
namespace Acme\ApiBundle\Tests;
class ApiWebTestCase extends WebTestCase
{
/**
* @var ReferenceRepository
*/
protected $fixturesRepo;
/**
* @var Client
*/
protected $authClient;
/**
* @var array
*/
private $fixtures = [];
protected function setUp()
{
$fixtures = array_merge([
'Acme\AppBundle\DataFixtures\ORM\LoadUserData'
], $this->fixtures);
$this->fixturesRepo = $this->loadFixtures($fixtures)->getReferenceRepository();
$this->authClient = $this->createAuthenticatedClient();
}
/**
* Create a client with a default Authorization header.
*
* @return \Symfony\Bundle\FrameworkBundle\Client
*/
protected function createAuthenticatedClient()
{
/** @var User $user */
$user = $this->fixturesRepo->getReference('user-1');
$jwtManager = $this->getContainer()->get('lexik_jwt_authentication.jwt_manager');
$token = $jwtManager->create($user);
$this->loginAs($user, 'api');
$client = static::makeClient([], [
'AUTHENTICATION' => 'Bearer ' . $token,
'CONTENT_TYPE' => 'application/json'
]);
$client->disableReboot();
return $client;
}
}
Now, the issue is that the injected UsernamePasswordToken
contains a User
instance which is detached from the current EntityManager
, thus resulting in the Doctrine error above.
I could merge the $user
object in the postAction
method into the EntityManager
but I don't want to do that because it means I modify my working code to make a test passes.
I've also tried directling merging the $user
object in my test into the EntityManager
like this:
$em = $client->getContainer()->get('doctrine')->getManager();
$em->merge($user);
But it's not working either.
So now, I'm stuck, I really don't know what to do except that I need to attach the user in session back to the current EntityManager
.
The error message you are getting indicates that the EntityManager contained in the test client's container doesn't know about your User entity. This leads me to believe that the way you are retrieving the User in your createAuthenticatedClient
method is using a different EntityManager.
I suggest you try to use the test kernel's EntityManager to retrieve the User entity instead. You can get it from the test client's container, for example.