1

I'm using the zfcuser doctrine module for my zf2 project with bjyauthorize, which is working quite fine. Now I'd like to get the connected Country entity out of my User entity

in User.php:

/**
 * An example of how to implement a role aware user entity.
 *
 * @ORM\Entity
 * @ORM\Table(name="users", indexes={
 *      @ORM\Index(name="fk_User_Country1_idx", columns={"Country_id"}), 
 * }, uniqueConstraints={@ORM\UniqueConstraint(name="email_UNIQUE", columns={"email"})})
 * @ORM\HasLifecycleCallbacks()
 */
class User implements UserInterface, ProviderInterface
{

...

/**
 * @var ersEntity\Country
 * @ORM\ManyToOne(targetEntity="Country", inversedBy="users")
 * @ORM\JoinColumn(name="Country_id", referencedColumnName="id")
 */
protected $country;

in Country.php

/**
 * Entity\Country
 *
 * @ORM\Entity()
 * @ORM\Table(name="Country")
 * @ORM\HasLifecycleCallbacks()
 */
class Country implements InputFilterAwareInterface
{

...

/**
 * @ORM\OneToMany(targetEntity="User", mappedBy="country")
 * @ORM\JoinColumn(name="id", referencedColumnName="Country_id")
 */
protected $users;

A simple testAction in one of my Controllers fails:

$user = $em->getRepository("ersEntity\Entity\User")
    ->findOneBy(array('id' => 1));
error_log($user->getFirstname().' '.$user->getSurname());
error_log('country: '.$user->getCountry()->getName());

which results in:

[Tue May 19 00:02:44 2015] [error] [client 185.17.207.16] Andi N.
[Tue May 19 00:02:44 2015] [error] [client 185.17.207.16] PHP Fatal error:  Call to a member function getName() on a non-object in /home/ers/www/ers/module/Admin/src/Admin/Controller/TestController.php on line 172

I'm wondering why it's not possible to get the Country entity from the User entity. With other entities in this same project this is working fine.

Can somebody tell me what needs to be done to be able to get the Country entity out of this zfcuser-bjyauthorize-doctrine User entity?

For more code info, this whole project is available at https://github.com/inbaz/ers in the develop branch.

EDIT:

With users who have no country set there needs to be an error. It's right that there is the need to check if a country exists. But this user has a country set. I checked that via phpmyadmin. It's not possible to get this country entity via the getCountry() method.

Maybe this is cause the deserializing and serializing of the doctrine entity into the session. I checked the doctrine documentation on how to save entities into the session. But I'd like to keep all subentities in the session, so in my case I have a order entity in the session which holds multiple package entities. Each package entity has one user and multiple item entities. When getting the order entity back from the session I'd like to be able to access all these elements.

I even tried to do a merge on each user in the session like:

foreach($participants as $participant) {
    $participant = $em->merge($participant);
}

but that doesn't change anything. Even a merge on the whole order was not successful.

Do you have an idea on how to get the doctrine entities back from the session with the full doctrine features?

bigandini
  • 106
  • 8

2 Answers2

0

It looks all fine to me. At first I thought your getCountry method was missing from your entity definition but I see it is there.

My guess is that user with id 1 does not have a Country set. Go to your table (phpmyadmin or whatever) and check the value of the Country_id column. If you want each user to have a country you can insure your data integrity by adding nullable=false to your join column definition according to the Doctrine2 @JoinColumn specs.

Otherwise (if $country is allowed to be null) you should maybe first check if country is an object before pulling getName():

$countryName = null;
$country = $user->getCountry();
if(is_object($country)){
    $countryName = $country->getName();
}
/** @var null|string $countryName */
$countryName  //... use your country name which is null or string

One more thing, I would strongly suggest to use only lowercase strings for table and column names. Using uppercase could get you into trouble.

EDIT

I took a closer look and see now that your mappings are wrong. Did you use doctrine to validate your schema? There is a @ORM\JoinColumn on the inverse side of the relationship (inside Country.php). The inverse side does not need this @ORM\JoinColumn declariation. You should remove this line. The owning side is User so the join column definition should be only declared there.

It should be like this:

Country.php:

/**
 * @var Collection
 * @ORM\OneToMany(targetEntity="User", mappedBy="country")
 */
protected $users;

User.php:

/**
 * @var Country
 * @ORM\ManyToOne(targetEntity="Country", inversedBy="users")
 * @ORM\JoinColumn(name="Country_id", referencedColumnName="id")
 */
protected $country;
Wilt
  • 41,477
  • 12
  • 152
  • 203
  • The users can choose a country but there is no need to. So country can be null. I validated my scheme before and after the deletion of the JoinColumn in Country.php. Both were ok with: [Mapping] OK - The mapping files are correct. [Database] OK - The database schema is in sync with the mapping files. Doctrine itself was not able to find an error here. Could that be a problem of deserialising and serialising the user entity into the session? After deserialisation it's not possible to get the Country entity anymore. – bigandini May 19 '15 at 11:21
  • Yes, you should follow [certain the documentation](http://doctrine-orm.readthedocs.org/en/latest/cookbook/entities-in-session.html#serializing-entity-into-the-session) when storing entities in the session. I would advise only to store ids in the session and simply resolve the objects again when you need them. – Wilt Sep 21 '15 at 17:37
0

Doctrine 2: Can entities be saved into sessions?

This is the answer to my question.

if a lazy-loaded entity is not loaded at serialization time, it won't be loadable after de-serialization. So you have to make sure the entity is fully loaded before serializing it.

There is still the question open if it's not possible to create a new doctrine entity and get an array copy of the de-serialized one and populate this data into the new entity.

Community
  • 1
  • 1
bigandini
  • 106
  • 8
  • I would suggest to not store the serialized entity in your session storage. Better is to only store the `user_id` and resolve the entity from the database. You could make a storage that is `ObjectManagerAware` and implement a `getUser` method so you can do `$sessionService->getUser()`. You get `user_id` from session storage and use an instance of `ObjectManager` to resolve your `User` entity in this `getUser` method. Like this you always have an instance of `User` with the latest data. – Wilt May 19 '15 at 14:08