Search code examples
phpsymfonydoctrinesymfony5

Symfony5; cant access joined entity values


in my add hours controller i can see and access the variables in the collection but when i try to access them in the maincontroller, i only get an empty collection, see maincontroller

 dd($projects[0]->getProjectHours());

My ProjectHours entity

/**
 * Class ProjectHours
 * @ORM\Entity
 */
class ProjectHours
{

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


    /**
     * @ORM\Column(type="datetime")
     */
    private $timestamp_start;


    /**
     * @ORM\Column(type="datetime")
     */
    private $timestamp_end;


    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Project", inversedBy="project_hours")
     * @ORM\JoinColumn(name="project_id", nullable=false, referencedColumnName="id", onDelete="CASCADE")
     */
    private $project;


    /**
     * @ORM\Column(type="dateinterval")
     */
    private $duration;


    public function addProjectHours(ProjectHours $ph)
    {
        $this->project_hours[] = $ph;
    }

    /**
     * @return Collection|ProjectHours[]
     */
    public function getProjectHours()
    {
        return $this->project_hours;
    }


My Project entity


/**
 * Class Project
 * @ORM\Entity
 */
class Project
{


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


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


    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="projects")
     * @ORM\JoinColumn(name="user_id", nullable=false, referencedColumnName="id")
     */
    private $user;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\ProjectHours", mappedBy="project", cascade={"persist", "remove"})
     */
    private $project_hours;



    public function addProjectHours(ProjectHours $ph)
    {
        $this->project_hours[] = $ph;
    }

    /**
     * @return Collection|ProjectHours[]
     */
    public function getProjectHours()
    {
        return $this->project_hours;
    }


My addHours controller

  #[Route('projects/{project}/new', name: 'app_newHours')]
    public function index(Request $request, $project): Response
    {

        $em=$this->getDoctrine()->getManager();
        $project = str_replace('%20', ' ', $project);

        $hour_entry = new ProjectHours();

        $hour_entry->setTimestampStart(new \DateTime('NOW'));
        $hour_entry->setTimestampEnd(new \DateTime('NOW'));

        $pj = $em->getRepository(Project::class)->findOneBy(array('name'=> $project));
        $hour_entry->setProject($pj);

        $form = $this->createForm(AddHoursClassType::class, $hour_entry );
        $form->handleRequest($request);


        if($form->isSubmitted() && $form->isValid())
        {
            $start = $hour_entry->getTimestampStart();
            $end = $hour_entry->getTimestampEnd();

            if($end > $start)
            {
                $interval = $start->diff($end);

                $hour_entry->setDuration($interval);

                $pj->addProjectHours($hour_entry);


                //store to database
                $em->persist($hour_entry);
                $em->persist($pj);
                $em->flush();
                $this->addFlash('success', 'Hours added successfully!');
            }
            else
            {
                $this->addFlash('error', 'End time must be later than start time!');
            }
        }

and finally in my Maincontroller

 /**
         * @Route("/projects", name="app_mainscreen")
         */
        public function Main()
        {
            $em = $this->getDoctrine()->getManager();
            $user = $this->getUser();
            $projects = $em->getRepository(Project::class)->findBy(array('user' => $user));
            $hourlist = $this->getHourList($projects, $em);

            dd($projects[0]->getProjectHours());


            return $this->render('home.html.twig', [
                'projectlist' => $projects,
                'hourlist' => $hourlist
            ]);
        }

If anyone can help me it would be highly appreciated!


Solution

  • That is because the collection just holds a reference to the entities until you access them (lazy loading), indicated by #initialized: false. Since you are dumping before accessing any contents of the collection, it appears to be empty. This behavior is designed to improve performance in cases where you may not want to accesss the collection, then the related entities do not need to be fetched.
    For debugging purposes, you can force all the items in the collection to load by converting the collection to an array with it's built-in method toArray:

    dd($projects[0]->getProjectHours()->toArray());
    

    Normally, the individual items should load as you iterate through the collection in your template (toArray is not necessary).

    {% for project in projectlist %}
      Project {{ project.name }} hours:
      <ul>
      {% for hour in project.projectHours %}
        <li>
          Started: {{ hour.timestampStart|date('g:ia D, M jS, Y') }}<br>
          Ended: {{ hour.timestampEnd|date('g:ia D, M jS, Y') }}    
        </li>
      {% endfor %}
      </ul>
    {% endfor %}