Buy

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

204 lines src/AppBundle/Entity/Genus.php
... 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!

204 lines src/AppBundle/Entity/Genus.php
... 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:

92 lines app/Resources/views/genus/show.html.twig
... 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:

92 lines app/Resources/views/genus/show.html.twig
... 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:

243 lines src/AppBundle/Entity/User.php
... 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:

56 lines app/Resources/views/user/show.html.twig
... 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:

92 lines app/Resources/views/genus/show.html.twig
... 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():

153 lines src/AppBundle/Controller/GenusController.php
... 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:

143 lines src/AppBundle/Controller/GenusController.php
... 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):

143 lines src/AppBundle/Controller/GenusController.php
... 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:

44 lines src/AppBundle/DataFixtures/ORM/fixtures.yml
... 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)>:

44 lines src/AppBundle/DataFixtures/ORM/fixtures.yml
... 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!

  • 2017-09-06 argy_13

    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! ;-)

  • 2017-09-04 Diego Aguiar

    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!

  • 2017-09-02 argy_13

    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! ;)

  • 2017-08-31 argy_13

    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!

  • 2017-08-28 Diego Aguiar

    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;
    ...
  • 2017-08-26 argy_13

    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

  • 2017-08-25 argy_13

    https://pastebin.com/92nBGTWs

    i hope that this will going to work!!

  • 2017-08-25 Diego Aguiar

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

  • 2017-08-25 argy_13

    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?

  • 2017-08-25 Diego Aguiar

    Hey argy_13

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

  • 2017-08-25 argy_13

    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 ;)

  • 2017-08-25 argy_13

    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

  • 2017-08-25 weaverryan

    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!

  • 2017-08-24 argy_13

    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 ;)

  • 2017-08-04 Diego Aguiar

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

  • 2017-08-04 Josk

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

  • 2017-08-04 Diego Aguiar

    Hey Josk!

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

    Cheers!

  • 2017-07-31 Josk

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

  • 2017-07-28 Diego Aguiar

    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!

  • 2017-07-28 Josk

    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

    ^_^

  • 2017-07-27 Diego Aguiar

    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!

  • 2017-07-26 Josk

    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

  • 2017-07-26 Diego Aguiar

    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!

  • 2017-07-26 Josk

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

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

  • 2017-07-25 Diego Aguiar

    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

  • 2017-07-25 Josk

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

    https://pastebin.com/i4jqLkMH

  • 2017-07-25 Diego Aguiar

    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)

  • 2017-07-25 Josk

    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

  • 2017-07-25 Diego Aguiar

    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;
  • 2017-07-25 Josk

    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

  • 2017-07-25 Diego Aguiar

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

  • 2017-07-24 Diego Aguiar

    Oh, I see, this is a very weird error, something in your metadata is wrong. Could you show me your entity code
    Does it fail when you submit the form ?

  • 2017-07-21 Josk

    Right, sorry.
    I followed the tutorial and it works 'till the edit part, but I have tested it only during the course tutorial, so I cannot say exactly at which point things went wrong on the edit page.
    I've created the project with the currently stable version 3.3, and I'm using the code from the course.
    You can see the screen of the error in the link above, thank you.

    http://imgur.com/a/Ih6Cu

  • 2017-07-21 Diego Aguiar

    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!

  • 2017-07-21 Josk

    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

  • 2017-01-16 Victor Bocharsky

    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!

  • 2017-01-16 Victor Bocharsky

    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!

  • 2017-01-16 Victor Bocharsky

    Hey ehymel ,

    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!

  • 2017-01-15 Daniel

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

  • 2017-01-15 ehymel

    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.

  • 2017-01-15 ehymel

    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?