Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Using the new OneToMany Collections

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Open up the genus/show.html.twig template. Actually, let's start in the Genus class itself. Find getGenusScientists():

... lines 1 - 14
class Genus
{
... lines 17 - 195
/**
* @return ArrayCollection|User[]
*/
public function getGenusScientists()
{
return $this->genusScientists;
}
}

This method is lying! It does not return an array of User objects, it returns an array of GenusScientist objects!

... lines 1 - 14
class Genus
{
... lines 17 - 195
/**
* @return ArrayCollection|GenusScientist[]
*/
public function getGenusScientists()
{
return $this->genusScientists;
}
}

In the template, when we loop over genus.genusScientists, genusScientist is not a User anymore. Update to genusScientist.user.fullName, and above, for the user_show route, change this to genusScientist.user.id:

... lines 1 - 4
{% block body %}
... lines 6 - 7
<div class="sea-creature-container">
<div class="genus-photo"></div>
<div class="genus-details">
<dl class="genus-details-list">
... lines 12 - 21
<dd>
<ul class="list-group">
{% for genusScientist in genus.genusScientists %}
<li class="list-group-item js-scientist-item">
<a href="{{ path('user_show', {
'id': genusScientist.user.id
}) }}">
{{ genusScientist.user.fullName }}
... line 30
</a>
... lines 32 - 41
</li>
{% endfor %}
</ul>
</dd>
</dl>
</div>
</div>
<div id="js-notes-wrapper"></div>
{% endblock %}
... lines 51 - 92

Then, in the link, let's show off our new yearsStudied field: {{ genusScientist.yearsStudied }} then years:

... lines 1 - 4
{% block body %}
... lines 6 - 7
<div class="sea-creature-container">
<div class="genus-photo"></div>
<div class="genus-details">
<dl class="genus-details-list">
... lines 12 - 21
<dd>
<ul class="list-group">
{% for genusScientist in genus.genusScientists %}
<li class="list-group-item js-scientist-item">
<a href="{{ path('user_show', {
'id': genusScientist.user.id
}) }}">
{{ genusScientist.user.fullName }}
({{ genusScientist.yearsStudied }} years)
</a>
... lines 32 - 41
</li>
{% endfor %}
</ul>
</dd>
</dl>
</div>
</div>
<div id="js-notes-wrapper"></div>
{% endblock %}
... lines 51 - 92

We still need to fix the remove link, but let's see how it looks so far!

Refresh! It's way less broken! Well, until you click to view the user!

Updating the User Template

To fix this, start by opening User and finding getStudiedGenuses(). Change the PHPDoc to advertise that this now returns an array of GenusScientist objects:

... lines 1 - 16
class User implements UserInterface
{
... lines 19 - 214
/**
* @return ArrayCollection|GenusScientist[]
*/
public function getStudiedGenuses()
{
return $this->studiedGenuses;
}
... lines 222 - 241
}

Next, go fix the template: user/show.html.twig. Hmm, let's rename this variable to be a bit more clear: genusScientist, to match the type of object it is. Now, update slug to be genusScientist.genus.slug. And print genusScientist.genus.name:

... lines 1 - 2
{% block body %}
<div class="container">
<div class="row">
... lines 6 - 38
<div class="col-xs-4">
<h3>Genus Studied</h3>
<ul class="list-group">
{% for genusScientist in user.studiedGenuses %}
<li class="list-group-item">
<a href="{{ path('genus_show', {
'slug': genusScientist.genus.slug
}) }}">
{{ genusScientist.genus.name }}
</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endblock %}

Try it! Page is alive!

Back on the genus page, the other thing we need to fix is this remove link. In the show.html.twig template for genus, update the userId part of the URL: genusScientist.user.id:

... lines 1 - 4
{% block body %}
... lines 6 - 7
<div class="sea-creature-container">
<div class="genus-photo"></div>
<div class="genus-details">
<dl class="genus-details-list">
... lines 12 - 21
<dd>
<ul class="list-group">
{% for genusScientist in genus.genusScientists %}
<li class="list-group-item js-scientist-item">
... lines 26 - 32
<a href="#"
class="btn btn-link btn-xs pull-right js-remove-scientist-user"
data-url="{{ path('genus_scientists_remove', {
genusId: genus.id,
userId: genusScientist.user.id
}) }}"
>
<span class="fa fa-close"></span>
</a>
</li>
{% endfor %}
</ul>
</dd>
</dl>
</div>
</div>
<div id="js-notes-wrapper"></div>
{% endblock %}
... lines 51 - 92

Next, find this endpoint in GenusController: removeGenusScientistAction():

... lines 1 - 14
class GenusController extends Controller
{
... lines 17 - 126
public function removeGenusScientistAction($genusId, $userId)
{
$em = $this->getDoctrine()->getManager();
/** @var Genus $genus */
$genus = $em->getRepository('AppBundle:Genus')
->find($genusId);
if (!$genus) {
throw $this->createNotFoundException('genus not found');
}
$genusScientist = $em->getRepository('AppBundle:User')
->find($userId);
if (!$genusScientist) {
throw $this->createNotFoundException('scientist not found');
}
$genus->removeGenusScientist($genusScientist);
$em->persist($genus);
$em->flush();
return new Response(null, 204);
}
}

It's about to get way nicer. Kill the queries for Genus and User. Replace them with $genusScientist = $em->getRepository('AppBundle:GenusScientist') and findOneBy(), passing it user set to $userId and genus set to $genusId:

... lines 1 - 14
class GenusController extends Controller
{
... lines 17 - 126
public function removeGenusScientistAction($genusId, $userId)
{
$em = $this->getDoctrine()->getManager();
$genusScientist = $em->getRepository('AppBundle:GenusScientist')
->findOneBy([
'user' => $userId,
'genus' => $genusId
]);
... lines 136 - 140
}
}

Then, instead of removing this link from Genus, we simply delete the entity: $em->remove($genusScientist):

... lines 1 - 14
class GenusController extends Controller
{
... lines 17 - 126
public function removeGenusScientistAction($genusId, $userId)
{
$em = $this->getDoctrine()->getManager();
$genusScientist = $em->getRepository('AppBundle:GenusScientist')
->findOneBy([
'user' => $userId,
'genus' => $genusId
]);
$em->remove($genusScientist);
$em->flush();
return new Response(null, 204);
}
}

And celebrate!

Go try it! Quick, delete that scientist! It disappears in dramatic fashion, and, when we refresh, it's definitely gone.

Phew! We're almost done. By the way, you can see that this refactoring takes some work. If you know that your join table will probably need extra fields on it, you can save yourself this work by setting up the join entity from the very beginning and avoiding ManyToMany. But, if you definitely won't have extra fields, ManyToMany is way nicer.

Updating the Fixtures

The last thing to fix is the fixtures. We won't set the genusScientists property up here anymore. Instead, scroll down and add a new AppBundle\Entity\GenusScientist section:

... lines 1 - 38
AppBundle\Entity\GenusScientist:
... lines 40 - 44

It's simple: we'll just build new GenusScientist objects ourselves, just like we did via newAction() in PHP code earlier. Add genus.scientist_{1..50} to create 50 links. Then, assign user to a random @user.aquanaut_* and genus to a random @genus_*. And hey, set yearsStudied to something random too: <numberBetween(1, 30)>:

... lines 1 - 38
AppBundle\Entity\GenusScientist:
genus.scientist_{1..50}:
user: '@user.aquanaut_*'
genus: '@genus_*'
yearsStudied: <numberBetween(1, 30)>

Nice! Go find your terminal and reload!

./bin/console doctrine:fixtures:load

Ok, go back to /genus... and click one of them. We have scientists!

So our app is fixed, right? Well, not so fast. Go to /admin/genus: you might need to log back in - password iliketurtles. Our genus form is still totally broken. Ok, no error: but it doesn't even make sense anymore: our relationship is now more complex than checkboxes can handle. For example, how would I set the yearsStudied?

Time to take this form up a level.

Leave a comment!

52
Login or Register to join the conversation
Ernest H. Avatar
Ernest H. Avatar Ernest H. | posted 5 years ago

Everything in this lesson works great for me right up until the end (time 5:27 in your video) where I click the edit link on the admin/genus page. Things blow up with "Cannot access private property AppBundle\Entity\GenusScientist::$id". I can't figure out why this is happening. I do have a "public function getId()" in my GenusScientist entity. I even copied your final version of this entity from the course files and the same thing happens, so this has to be coming from somewhere else.

Any hints?

1 Reply
Ernest H. Avatar

For what it's worth, if I change the scope of $id to public (rather than private) in the GenusScientist entity, then all works fine.

Reply

Ah, it was good for debugging, now we know exactly what the problem is, but we definitely should find the place where the private `id` property is called outside the GenusScientist class and fix it.

Cheers!

Reply
Default user avatar

Hi Victor, i just can say about it that the problem is the same for me and i found the problem, but i can t understand it. In the code of GenusFormType.php, if i erase the line

'expanded' => true,

from the

->add('genusScientists', EntityType::class, [
'class' => User::class,
'multiple' => true,
'expanded' => true,
'choice_label' => 'email',
'query_builder' => function(UserRepository $repo){
return $repo->createIsScientistQueryBuilder();
}
])

it works perfect (of course without checkboxes).
Also in the next lesson that you re changing the code there is none problem at all!

I hope it helped a little bit!!! Keep going with the perfect work ;)

Reply

Yo argy_13!

Thanks for sharing! Yea... this is a mystery indeed :). And this is an interesting clue! Before you posted this, I was pretty confident that "expanded" is really a superficial option: it just controls how the elements are rendered... and not much more. But, now I think I'm wrong! I guess it's not a huge deal, but if you're able to get this error again, a screenshot of the full stacktrace might be enough to crack it finally!

Cheers!

1 Reply
Default user avatar

Hi Ryan!
I tried to change just this part again (because i finished the 21st lesson, so i changed my code for 3 more lesson and i don t know the consequences to this error). I put back the code for

->add('genusScientists',....

with 'expanded' as before and i got the same error, but i don t know if it mention the same problems.. here is the page with the error

Reply

Hey argy_13

I think you forgot to paste the page's url :)

Reply
Default user avatar

Diego, I pasted the whole page but it didn t upload these 2 replies... i saw it right now! Maybe because it was too big..
I will try again, but do you want to send me an email adress to send both the document and the print screen?

Reply

Would be easier if you upload it to https://pastebin.com/ and share me the URL :)

Reply
Default user avatar

https://pastebin.com/92nBGTWs

i hope that this will going to work!!

Reply

Hey argy_13!

Sorry for the late response. This is very interesting, for some reason it cannot access to your ID property via reflection, I would like to test something, change the scope to public and try it again.


// GenusScientist.php
...
public $id;
...
Reply
Default user avatar

Hi Diego, my reply is also late, but sorry! :)
Unfortunately, i m not in this chapter any more, but the next days when i ll find time i will try to put it in the specific point and then turn it to public to give you the errors. I hope i will do it soon that you find the bug.

Cheers!

1 Reply
Default user avatar

Hi Diego,
i did all the lessons just to help you with this!

If i do it

// GenusScientist.php
...
public $id;

it will work perfectly.

Also, if i remove the line

'expanded' => true,

from the GenusFormType.php

If you want something else from me i can keep it for 3-4 days more like this!

I m sure that you ll find the solution! ;)

Reply

Hey argy_13

Thanks for taking your time to answer me :)

As I expected, it just cannot access to the property because something weird happens when setting to true the 'expanded' option... I don't know why this happens but it's very interesting!

Reply
Default user avatar

It s ok, Diego! if you want to ask me to do any test and you say me what i have to examine, you can say it! ;-)

1 Reply
Default user avatar

Just to mention that i have the exact same error message in the 23rd lesson at the 4:03 when we try to reach the edit for the update user (you don t use it in the lesson because you re erasing all the code for save genus from User s entity)

Cannot access private property AppBundle\Entity\GenusScientist::$id

Also the problem is the 'expanded' from the UserEditForm

Reply
Default user avatar

If you want also the

Stack Trace (Plain Text)
i have saved it to a document so i can upload it

I hope i helped a litlle bit
Keep your wonderful work ;)

Reply

I have the same issue, it has to be something in the GenusAdminController editAction or in the GenusFormType

Reply

Hey Daniel,

Yes, it makes sense. Try to find the private `id` property call in those files. If you don't find any calls, then you can try my suggestion here: https://knpuniversity.com/s...

Cheers!

Reply

Hey Ernest H. ,

Hm, it's weird... if you sure you have the exactly public function getId() inside of GenusScientist entity, so I bet you have a direct call of ->id somewhere in your PHP files, because Twig should resolve the public getter method automatically when you call {{ genusScientist.id }}. I think the easiest way is to find all ->id calls in your PHP files. If you use PhpStorm, then you can select src/ dir from the project files in the right sidebar and press Shift + Command + F on Mac (or right click on src/ and then choose "Find in path..."). Then enter the ->id text to find and check the result. Let me know if you find some "->id" calls on a GenusScientist object except the one inside the getId() method.

Cheers!

Reply
Alessandro-D Avatar
Alessandro-D Avatar Alessandro-D | posted 3 years ago | edited

Hi Ryan (or any of his colleagues)
I have spent over a day in trying to resolve this issue and it really start to frustrate me.
Basically I watched the tutorial of "ManyToMany with extra field" a bunches of time and followed the tutorial by the letter, but I can't seems to be able to save/remove items.
A bit of history. I have a User entity and a Social Entity. Originally, I created a new field in the User called "socials" having ManyToMany relationship with the Social Entity. This created all methods needed in the User and Social classes, as well as creating an additional UserSocial entity.
I then followed the tutorial to change the ManyToMany into OneToMany, but when I try to edit a user profile, I cannot seems to get around the saving/removing problem.
Here is what I have:


Entity\User
    /**
     * @ORM\OneToMany(targetEntity="App\Entity\UserSocial", mappedBy="user")
     */
    private $socials;

    /**
     * @return Collection|Social[]
     */
    public function getSocials(): Collection
    {
        return $this->socials;
    }

    public function addSocial(Social $social): self
    {
        if (!$this->socials->contains($social)) {
            $this->socials[] = $social;
        }

        return $this;
    }

    public function removeSocial(Social $social): self
    {
        if ($this->socials->contains($social)) {
            $this->socials->removeElement($social);
        }

        return $this;
    }

Entity\Social

class Social
{

/**
 * @ORM\Id()
 * @ORM\GeneratedValue()
 * @ORM\Column(type="integer")
 */
private $id;

/**
 * @ORM\Column(type="string", length=100)
 */
private $name;

/**
 * @ORM\Column(type="string", length=100, nullable=true)
 */
private $icon;

/**
 * @ORM\OneToMany(targetEntity="App\Entity\UserSocial", mappedBy="social")
 */
private $users;

public function __construct()
{
    $this->users = new ArrayCollection();
}

public function getId(): ?int
{
    return $this->id;
}

public function getName(): ?string
{
    return $this->name;
}

public function setName(string $name): self
{
    $this->name = $name;

    return $this;
}

public function getIcon(): ?string
{
    return $this->icon;
}

public function setIcon(?string $icon): self
{
    $this->icon = $icon;

    return $this;
}

public function __toString()
{
    return (string) $this->getName();
}

/**
 * @return Collection|User[]
 */
public function getUsers(): Collection
{
    return $this->users;
}

public function addUser(User $user): self
{
    if (!$this->users->contains($user)) {
        $this->users[] = $user;
        $user->addSocial($this);
    }

    return $this;
}

public function removeUser(User $user): self
{
    if ($this->users->contains($user)) {
        $this->users->removeElement($user);
        $user->removeSocial($this);
    }

    return $this;
}

}


Entity\UserSocial
/**
 * @ORM\Entity
 * @ORM\Table(name="user_social")
 */
class UserSocial
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="socials")
     * @ORM\JoinColumn(nullable=false)
     */
    private $user;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Social", inversedBy="users")
     * @ORM\JoinColumn(nullable=false)
     */
    private $social;
    /**
     * @ORM\Column(type="string")
     */
    private $url;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return mixed
     */
    public function getUser()
    {
        return $this->user;
    }

    /**
     * @param mixed $user
     */
    public function setUser($user): void
    {
        $this->user = $user;
    }

    /**
     * @return mixed
     */
    public function getSocial()
    {
        return $this->social;
    }

    /**
     * @param mixed $social
     */
    public function setSocial($social): void
    {
        $this->social = $social;
    }

    /**
     * @return mixed
     */
    public function getUrl()
    {
        return $this->url;
    }

    /**
     * @param mixed $url
     */
    public function setUrl($url): void
    {
        $this->url = $url;
    }

}

In my ProfileFormType, I have 'socials' mapped as CollectionType


            ->add('socials', CollectionType::class, [
                'entry_type' => TextType::class,
                'allow_add' => true
            ])

in my ProfileController, I have something like that:


$socialMediaList = $em->getRepository('App:Social')->findAllWithUserValues();
$userProfileModel =  new ProfileFormModel();
$userProfileModel->socials = $socialMediaList;
`</pre >

The findAllWithUserValues  has a raw SQL query that retrieve all information I needed (I used the raw SQL because I spent hours in trying to figure out how to use DQL, but with no success

public function findAllWithUserValues()
{

    $conn = $this->getEntityManager()->getConnection();
    $sql = '
        SELECT social.*, us.url 
        FROM social 
        LEFT JOIN user_social us ON social.id = us.social_id AND us.user_id = 1
    ';
    $stmt = $conn->prepare($sql);
    $stmt->execute();
    return $stmt->fetchAll();

}



end in twig, I render it like this:

{% set vars = profileEditForm.socials.vars %}
{% set socialMediaList = profileEditForm.socials.vars.data %}
{% for social in socialMediaList %}
<input type="text" name="{{ vars.full_name }}[{{ social.name }}]" {{ vars.attr.required is defined ? 'required' }} class="form-control" placeholder="{{ social.name }}" value="{{ social.url ?: '' }}" />



Now, what I noticed is that the actual data I need to add is inside the user_social table, therefore, when I do $user->addSocial(), it expect a Social, but I am confused because it would make sense to pass a UserSocial instance. I actually tried to change it so that it expects a UserSocial, but by doing that, I also had to add "cascade={"persist"}. If I did that, it would actually save it to user_social table, but then I got all confused on the removal of the Social from that table.

I am sorry if this thread is very long, but I really hope you can help. I have tried help on skack, google, codementor and I can't get my head around the proper way of saving/removing a ManyToMany with extra field.

Thanks a lot (and sorry again for this long message).
Reply

Hey Alessandro,

First of all, I'd recommend you to rename some field. If we're talking about a field that contain collection of UserSocial entities, then call the field as $userSocials instead of just $socials, especially when you have Social entity. This will not mislead you what exactly entity we're talking about: UserSocial or Social. It's minor , but just a friendly advice. Also, after all complex manipulations... or actually after any manipulations with entity mapping I'd recommend you to run a special command that helps to validation if your mapping is valid and if your DB is in sync with the current mapping. Run "bin/console doctrine:schema:validate" - if it's green - perfect! Less chances you did something wrong. If it's red - then most probably your problem is related to the output. Try to figure out what's wrong exactly and fix it. So, first of all, please, double check it so we know mapping is correct. At the first sight it looks good for me.

I noticed that you use "model" in controller, like ProfileFormModel. Are you building the form type base on this model? If so, like if you map the form to a model, not entity, then you will need to write a custom logic where you will handle the model and map all the data to real entities, like iterate over collections and create new real entities for them. And of course, every new entity you would need to persist first before calling flush. You may want to debug the final entity, use "dd()" or "dump(); die;" to dump the final data and manually check if all the fields are set correctly.

But if you map your form type to an entity - then try to debug the final data at least to make sure they look good.

So, yes, I see why you are confusing, because we're talking about different entities. Do not confuse Social, User and SocialUser entities - all are different, and you do need to operate proper entities when you're trying to set them in setters. To have less WTF moments I'd suggest you to add typehints in your setters, like if you call setUser(), you only allow to pass User objects. If you call setUserSocial() - then only UserSocial are allowed. Typehints will help you a lot to avoid setting wrong object types.

And also, if you have cascade={persist} annotation - it won't mean to be saved to the DB unless you call flush. So, you would need to do any manipulations first, add/remove necessary objects and only then call flush(). But I'd recommend you to write a custom logic and call persist() explicitly on those entities you would like to save with flush() later. That annotation adds some magic and you can miss something important. So, doing it manually will be easier to understand I think.

Also, did you try to implement this way of complex manyToMany (i.e. oneToMany-ManyToOne) relation following this tutorial? Or did you start implementing this approach in your own project? I'd recommend you to follow the video exactly to implement the same things we show in this video. It will help you to understand the approach better. And then, when you successfully done what we show in this course, try to implement the same in your own project. But this time you should better understand what's going on there.

I hope this helps!

Cheers!

Reply
Sara Avatar

I'm getting a twig error when it hits the loop.
[2/2] Twig_Error_Runtime: An exception has been thrown during the rendering of a template ("Notice: Undefined index: genus").
{% for genusScientist in genus.scientists %}

I named my variable scientists instead of genusScientists but that shouldn't matter.

Any ideas?

Reply
Osagie Avatar

Hey Sara,

So, somewhere you're calling "something.genus", and that "something" variable does not have a genus index. Please, notice the line where you have this error and try to debug, you can use "dump(something)" function for help.

Cheers!

Reply

Hmm, I can't see the doctrine's metadata, are you using yaml ?

Reply
Default user avatar

I don't know why, but if I edit the post I see the whole code, but when published is not complete. Anyway, I'll link the code. It's simple php

https://pastebin.com/GvTSbfMv

Reply

Oh, it must be a thing from Disqus

I'm not really sure about this, but try writing the full namespace of your entities in your relationships, like:


   /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Genus", inversedBy="genusScientists")
     * @ORM\JoinColumn(nullable=false)
     */
    private $genus;
Reply
Default user avatar

Nope. I've also cleared the cache and the drop//create/migrate/load procedure, but I still got the error.
I'll give you also the Genus code, I don't know, maybe it's there.

https://pastebin.com/Eeybhgpy

Reply

Hmm, interesting... Try clearing doctrine's cache
bin/console doctrine:cache:clear-metadata

Can you show me the full error please ? (message + full stack trace)

Reply
Default user avatar

Sure, in this text there is message + full trace + plain text version. I hope It will be useful

https://pastebin.com/i4jqLkMH

Reply

I think your problem is in your FormType, I will need to see the code too :)
Maybe you are not correctly setting up the class field option for your GenusScientist property

Reply
Default user avatar

Allright, I'll link the whole code. Thank you :)

https://mega.nz/#!flQxVToD
key: !CaQhhmWzJnrVAVRw0x2qgkGP-1keUNowR8ZW5FMLhb0

Reply

Hey Josk

Finally I could track down your problem! :)
It is in your GenusFormType, you specified User class for your "genusScientists" field on Genus, just change it to "GenusScientist" class and everything should work (or at least you won't have that error again)

Cheers!

Reply
Default user avatar

Boom! :)
The good news is that the error is gone, the bad news is that you were right when you said "that error again".
Here's the new one:

https://pastebin.com/BhRhWBx5

Sorry to bother again and again

Reply

Hey Jost!

Hahaha, don't worry, this time is much easier, you have a tiny problem, your method is called "getGenusScientists" with an "S" at the end, and Doctrine is expecting it without an "s", is a small problem for plural words, just remove the "s" and everything will work just fine

Cheers!

Reply
Default user avatar

And we are back again to the same previous error "Given object is not an instance of the class this property was declared in
500 Internal Server Error - ReflectionException"
in vendor\doctrine\orm\lib\Doctrine\ORM\Mapping\ClassMetadataInfo.php at line 731 -
}
$id = $this->identifier[0];
$value = $this->reflFields[$id]->getValue($entity);
if (null === $value) {
return array();
at ReflectionProperty ->getValue (object(GenusScientist))
in vendor\doctrine\orm\lib\Doctrine\ORM\Mapping\ClassMetadataInfo.php at line 731 +
at ClassMetadataInfo ->getIdentifierValues (object(GenusScientist))
in vendor\symfony\symfony\src\Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader.php at line 125

^_^

Reply

If the problem is the same, the fix will be almost the same :)

I see your query builder for 'genusScientists' field expects an UserRepository, instead of GenusScientistRepository, that might be the problem, or maybe any other field has defined a wrong type of class (like you had before)

Cheers!

Reply
Default user avatar

I gave up :( I will take the finish folder and see the diff, It should work :)

Reply

Hey Josk!

Sorry for the late response, did it work ?
Uhh, we were just getting fun ;)

Cheers!

Reply
Default user avatar

Yes, It did, but I can't tell exactly what was the problem: there were a lot of Scientist/Scientists mistake :)

Reply

Oh, I see. Well, I'm happy that you can keep going learning :)

Reply
Default user avatar
Default user avatar Krzysztof | posted 5 years ago

Hi, in the end you wrote that should be no errors in the admin area. On admin/genus everything works but when I click on edit (admin/genus/13/edit) - huge error:

Type error: Argument 1 passed to AppBundle\Form\GenusFormType::AppBundle\Form\{closure}() must be an instance of AppBundle\Repository\UserRepository, instance of Doctrine\ORM\EntityRepository given

and it shows me:

in src\AppBundle\Form\GenusFormType.php (line 57)

->add('genusScientists', EntityType::class, [
'class' => GenusScientist::class,
'multiple' => true,
'expanded' => true,
'choice_label' => 'email',
'query_builder' => function (UserRepository $repo) {
return $repo->createIsScientistQueryBuilder();
}
])

What is wrong? I'm using Symfony 3.3.

Reply
Default user avatar

Oh, and If I remove this part:

'query_builder' => function (UserRepository $repo) {
return $repo->createIsScientistQueryBuilder();
}

I get other error:

Neither the property "email" nor one of the methods "getEmail()", "email()", "isEmail()", "hasEmail()", "__get()" exist and have public access in class "AppBundle\Entity\GenusScientist".

**********

I noticed one more thing:

If I go to: users/{id}/edit - and choose ID which is a scientist I get error:

Given object is not an instance of the class this property was declared in

If choose ID which is not a scientist the form is showing. But when I check some checkboxes and click update I get the same error as above.

Please help. :)

Reply

Hey Krzysztof

You have a tiny error in your field definition. You specified GenusScientist as a class for the field `genusScientists`, when it should be the User class instead. Try again doing that change, and if that doesn't work, let us know!

Have a nice day :)

Reply
Default user avatar

Hello, yes I had User but it gave me other error:

Given object is not an instance of the class this property was declared in.

Some other user (Josk, you can see below) had the same problem here and you wrote him this:

"It is in your GenusFormType, you specified User class for your "genusScientists" field on Genus, just change it to "GenusScientist" class and everything should work (or at least you won't have that error again)"

So I did it too...but this gave me error which I described in first my comment.

Reply

Ohh, forgive me, I meant `GenusScientist` class (instead of User class), when using a custom query builder you have to specify the same class as the relationship.
Have you tried doing it the "embedded" way? (Look at the next chapter)

If nothing works for you, can you upload your code to somewhere, so I can give it a quick look?

Cheers!

Reply
Default user avatar

Thanks for quick reply. I did the next tutorial and editing genuses works. :) I still don't know why it didn't work earlier.

However I still have a problem which I mention in my other comment below. I mean this:

"If I go to: users/{id}/edit - and choose ID which is a scientist I get error:

Given object is not an instance of the class this property was declared in

If choose ID which is not a scientist the form is showing. But when I check some checkboxes and click update I get the same error as above."

Should it already works or maybe it will be fixed in next lessons?

If you want to look I uploaded my project here (without var and vendor folders): http://gryzli83.ayz.pl/aqua...

Reply

Hey Krzysztof, sorry for my late response!

I think I found your problem. Open your User class and look at your property studiedGenuses, it has a relationship with GenusScientist, everything good so far, but now, check at your UserEditForm, you specified that the studiedGenuses field is a Genus type, it should be the same as your relationship. Do that change and I believe everything will work just nice :)

Cheers!

Reply
Default user avatar

Hi, I have a different message of error: Given object is not an instance of the class this property was declared in
500 Internal Server Error - ReflectionException.
The admin page has no error. Do you have some ideas?
Thanks

Reply

Hey Josk

Could you bring us some more information so we can help you ?

By doing what you get this error ?
Can you show me the full error message (with stack trace) ?
Which version of symfony are you using ?

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This course is built on Symfony 3, but most of the concepts apply just fine to newer versions of Symfony.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.1.3",
        "symfony/symfony": "3.4.*", // v3.4.49
        "doctrine/orm": "^2.5", // 2.7.5
        "doctrine/doctrine-bundle": "^1.6", // 1.12.13
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.4.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.6.7
        "symfony/monolog-bundle": "^2.8", // v2.12.1
        "symfony/polyfill-apcu": "^1.0", // v1.23.0
        "sensio/distribution-bundle": "^5.0", // v5.0.25
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.29
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.4
        "composer/package-versions-deprecated": "^1.11", // 1.11.99.4
        "knplabs/knp-markdown-bundle": "^1.4", // 1.9.0
        "doctrine/doctrine-migrations-bundle": "^1.1", // v1.3.2
        "stof/doctrine-extensions-bundle": "^1.2" // v1.3.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.7
        "symfony/phpunit-bridge": "^3.0", // v3.4.47
        "nelmio/alice": "^2.1", // v2.3.6
        "doctrine/doctrine-fixtures-bundle": "^2.3" // v2.4.1
    }
}
userVoice