I'm having trouble understanding what I'm doing wrong here. I have a "Project" entity that has a relation (ManyToMany) with another entity, "Service". In turn, Service is related to a "Task" entity, which is itself related to a "Section" entity. In the ProjectType I create a form field using FormBuilder for the property that identifies the Project - Service relation. In the twig template I'm trying to access Service's properties. I can't seem to access the property "section" of the task property in Service.

Project entity

<?php
/**
 * App_Entity_Project
 */

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Eleva\BackofficeBundle\Entity\BaseEntity;
use App\Repository\ProjectRepository;
use Doctrine\ORM\Mapping as ORM;

/**
 * Class Project
 *
 * Main Project entity.
 * @author Eleva
 * @package App\Entity
 * @license © 2023 Eleva SRL
 * @ORM\Entity(repositoryClass=ProjectRepository::class)
 */
class Project extends BaseEntity
{
    /**
     * @var int|null $id
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private ?int $id = null;

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

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

    /**
     * @ORM\Column(type="text", nullable=true)
     */
    private $notes;

    /**
     * @ORM\ManyToOne(targetEntity=Customer::class, inversedBy="projects")
     * @ORM\JoinColumn(nullable=false)
     */
    private $customer;

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

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

    /**
     * @ORM\ManyToMany(targetEntity=Service::class, inversedBy="projects")
     */
    private $services;

    /**
     * @ORM\OneToMany(targetEntity=ProjectProduct::class, mappedBy="project", cascade={"persist"})
     */
    private $projectProducts;

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

    /**
     * getId
     *
     * Returns the id value.
     */
    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 getSoReferral(): ?string
    {
        return $this->soReferral;
    }

    public function setSoReferral(?string $soReferral): self
    {
        $this->soReferral = $soReferral;

        return $this;
    }

    public function getNotes(): ?string
    {
        return $this->notes;
    }

    public function setNotes(?string $notes): self
    {
        $this->notes = $notes;

        return $this;
    }

    public function getCustomer(): ?Customer
    {
        return $this->customer;
    }

    public function setCustomer(?Customer $customer): self
    {
        $this->customer = $customer;

        return $this;
    }

    public function getPm(): ?string
    {
        return $this->pm;
    }

    public function setPm(?string $pm): self
    {
        $this->pm = $pm;

        return $this;
    }

    public function getDescription(): ?string
    {
        return $this->description;
    }

    public function setDescription(?string $description): self
    {
        $this->description = $description;

        return $this;
    }

    /**
     * @return Collection<int, Service>
     */
    public function getServices(): Collection
    {
        return $this->services;
    }

    public function addService(Service $service): self
    {
        if (!$this->services->contains($service)) {
            $this->services[] = $service;
        }

        return $this;
    }

    public function removeService(Service $service): self
    {
        $this->services->removeElement($service);

        return $this;
    }

    /**
     * @return Collection<int, ProjectProduct>
     */
    public function getProjectProducts(): Collection
    {
        return $this->projectProducts;
    }

    public function addProjectProduct(ProjectProduct $projectProduct): self
    {
        if (!$this->projectProducts->contains($projectProduct)) {
            $this->projectProducts[] = $projectProduct;
            $projectProduct->setProject($this);
        }

        return $this;
    }

    public function removeProjectProduct(ProjectProduct $projectProduct): self
    {
        if ($this->projectProducts->removeElement($projectProduct)) {
            // set the owning side to null (unless already changed)
            if ($projectProduct->getProject() === $this) {
                $projectProduct->setProject(null);
            }
        }

        return $this;
    }
}

Service entity

<?php
/**
 * App_Entity_Service
 */

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Eleva\BackofficeBundle\Entity\BaseEntity;
use App\Repository\ServiceRepository;
use Doctrine\ORM\Mapping as ORM;

/**
 * Class Service
 *
 * Main Service entity.
 * @author Eleva
 * @package App\Entity
 * @license © 2023 Eleva SRL
 * @ORM\Entity(repositoryClass=ServiceRepository::class)
 */
class Service extends BaseEntity
{
    /**
     * @var int|null $id
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private ?int $id = null;

    /**
     * @ORM\Column(type="text", nullable=true)
     */
    private $description;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $estimatedTime;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $estimatedTimeAway;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $numberOfTechnicians;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $timeAwayTechnicians;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $totalEstimatedHours;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $actualTime;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $hoursAway;

    /**
     * @ORM\Column(type="integer", nullable=true)
     */
    private $actualHoursAway;

    /**
     * @ORM\ManyToOne(targetEntity=JobPosition::class, inversedBy="services")
     */
    private $jobPosition;

    /**
     * @ORM\ManyToMany(targetEntity=Project::class, mappedBy="services")
     */
    private $projects;

    /**
     * @ORM\ManyToOne(targetEntity=Task::class, inversedBy="services")
     */
    private $task;

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

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

    /**
     * getId
     *
     * Returns the id value.
     */
    public function getId(): ?int
    {
        return $this->id;
    }

    public function getDescription(): ?string
    {
        return $this->description;
    }

    public function setDescription(?string $description): self
    {
        $this->description = $description;

        return $this;
    }

    public function getEstimatedTime(): ?int
    {
        return $this->estimatedTime;
    }

    public function setEstimatedTime(?int $estimatedTime): self
    {
        $this->estimatedTime = $estimatedTime;

        return $this;
    }

    public function getEstimatedTimeAway(): ?int
    {
        return $this->estimatedTimeAway;
    }

    public function setEstimatedTimeAway(?int $estimatedTimeAway): self
    {
        $this->estimatedTimeAway = $estimatedTimeAway;

        return $this;
    }

    public function getNumberOfTechnicians(): ?int
    {
        return $this->numberOfTechnicians;
    }

    public function setNumberOfTechnicians(?int $numberOfTechnicians): self
    {
        $this->numberOfTechnicians = $numberOfTechnicians;

        return $this;
    }

    public function getTimeAwayTechnicians(): ?int
    {
        return $this->timeAwayTechnicians;
    }

    public function setTimeAwayTechnicians(?int $timeAwayTechnicians): self
    {
        $this->timeAwayTechnicians = $timeAwayTechnicians;

        return $this;
    }

    public function getTotalEstimatedHours(): ?int
    {
        return $this->totalEstimatedHours;
    }

    public function setTotalEstimatedHours(?int $totalEstimatedHours): self
    {
        $this->totalEstimatedHours = $totalEstimatedHours;

        return $this;
    }

    public function getActualTime(): ?int
    {
        return $this->actualTime;
    }

    public function setActualTime(?int $actualTime): self
    {
        $this->actualTime = $actualTime;

        return $this;
    }

    public function getHoursAway(): ?int
    {
        return $this->hoursAway;
    }

    public function setHoursAway(?int $hoursAway): self
    {
        $this->hoursAway = $hoursAway;

        return $this;
    }

    public function getActualHoursAway(): ?int
    {
        return $this->actualHoursAway;
    }

    public function setActualHoursAway(?int $actualHoursAway): self
    {
        $this->actualHoursAway = $actualHoursAway;

        return $this;
    }

    public function getJobPosition(): ?JobPosition
    {
        return $this->jobPosition;
    }

    public function setJobPosition(?JobPosition $jobPosition): self
    {
        $this->jobPosition = $jobPosition;

        return $this;
    }

    /**
     * @return Collection<int, Project>
     */
    public function getProjects(): Collection
    {
        return $this->projects;
    }

    public function addProject(Project $project): self
    {
        if (!$this->projects->contains($project)) {
            $this->projects[] = $project;
            $project->addService($this);
        }

        return $this;
    }

    public function removeProject(Project $project): self
    {
        if ($this->projects->removeElement($project)) {
            $project->removeService($this);
        }

        return $this;
    }

    public function getTask(): ?Task
    {
        return $this->task;
    }

    public function setTask(?Task $task): self
    {
        $this->task = $task;

        return $this;
    }

    public function getOvertime(): ?string
    {
        return $this->overtime;
    }

    public function setOvertime(string $overtime): self
    {
        $this->overtime = $overtime;

        return $this;
    }
}

Task entity

<?php
/**
 * App_Entity_Task
 */

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Eleva\BackofficeBundle\Entity\BaseEntity;
use App\Repository\TaskRepository;
use Doctrine\ORM\Mapping as ORM;

/**
 * Class Task
 *
 * Main Task entity.
 * @author Eleva
 * @package App\Entity
 * @license © 2023 Eleva SRL
 * @ORM\Entity(repositoryClass=TaskRepository::class)
 */
class Task extends BaseEntity
{
    /**
     * @var int|null $id
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private ?int $id = null;

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

    /**
     * @ORM\ManyToOne(targetEntity=ServiceSection::class, inversedBy="tasks")
     * @ORM\JoinColumn(nullable=false)
     */
    private $section;

    /**
     * @ORM\OneToMany(targetEntity=Service::class, mappedBy="task", cascade={"persist"})
     */
    private $services;

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

    /**
     * getId
     *
     * Returns the id value.
     */
    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 getSection(): ?ServiceSection
    {
        return $this->section;
    }

    public function setSection(?ServiceSection $section): self
    {
        $this->section = $section;

        return $this;
    }

    /**
     * @return Collection<int, Service>
     */
    public function getServices(): Collection
    {
        return $this->services;
    }

    public function addService(Service $service): self
    {
        if (!$this->services->contains($service)) {
            $this->services[] = $service;
            $service->setTask($this);
        }

        return $this;
    }

    public function removeService(Service $service): self
    {
        if ($this->services->removeElement($service)) {
            // set the owning side to null (unless already changed)
            if ($service->getTask() === $this) {
                $service->setTask(null);
            }
        }

        return $this;
    }
}

ServiceSection entity

<?php
/**
 * App_Entity_ServiceSection
 */

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Eleva\BackofficeBundle\Entity\BaseEntity;
use App\Repository\ServiceSectionRepository;
use Doctrine\ORM\Mapping as ORM;

/**
 * Class ServiceSection
 *
 * Main ServiceSection entity.
 * @author Eleva
 * @package App\Entity
 * @license © 2023 Eleva SRL
 * @ORM\Entity(repositoryClass=ServiceSectionRepository::class)
 */
class ServiceSection extends BaseEntity
{
    /**
     * @var int|null $id
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     */
    private ?int $id = null;

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

    /**
     * @ORM\OneToMany(targetEntity=Task::class, mappedBy="section")
     */
    private $tasks;

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

    /**
     * getId
     *
     * Returns the id value.
     */
    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;
    }

    /**
     * @return Collection<int, Task>
     */
    public function getTasks(): Collection
    {
        return $this->tasks;
    }

    public function addTask(Task $task): self
    {
        if (!$this->tasks->contains($task)) {
            $this->tasks[] = $task;
            $task->setSection($this);
        }

        return $this;
    }

    public function removeTask(Task $task): self
    {
        if ($this->tasks->removeElement($task)) {
            // set the owning side to null (unless already changed)
            if ($task->getSection() === $this) {
                $task->setSection(null);
            }
        }

        return $this;
    }
}

ProjectType excerpt

$serviceBuilder = $builder->create('services', ServiceType::class, [
            'required' => false,
            'by_reference' => true,
            'data_class' => Service::class
        ]);

ServiceType excerpt

$builder->add('task', EntityType::class, [
            'required' => false,
            'class' => \App\Entity\Task::class,
            'multiple' => false,
            'expanded' => false,
            'mapped' => true,
            'choice_label' => 'name',
            'empty_data' => '',
            'constraints' => [],
            'query_builder' => function (EntityRepository $er) {
                return $er->createQueryBuilder('u')
                    ->where('u.del = 0 ')
                    ->orderBy('u.id', 'DESC');
            },
            'row_attr' => [
                'class' => 'container_task_id',
                'id' => 'container_task_id'
            ],
            'attr' => [
                'class' => 'selectize',
                'data-field-column' => 'task_id',
                'data-field-name' => 'task'
            ]
        ]);

TaskType excerpt

$builder->add('section', EntityType::class, [
            'required' => false,
            'class' => \App\Entity\ServiceSection::class,
            'multiple' => false,
            'expanded' => false,
            'mapped' => true,
            'choice_label' => 'name',
            'empty_data' => '',
            'constraints' => [],
            'query_builder' => function (EntityRepository $er) {
                return $er->createQueryBuilder('u')
                    ->where('u.del = 0 ')
                    ->orderBy('u.id', 'DESC');
            },
            'row_attr' => [
                'class' => 'container_service_section_id',
                'id' => 'container_service_section_id'
            ],
            'attr' => [
                'class' => 'selectize',
                'data-field-column' => 'service_section_id',
                'data-field-name' => 'section'
            ]
        ]);

What I'm trying to do is render the section property of task as a dropdown

<div class="flex-col col-1-2 container_service_section_id">
                                <h6 class="required">
                                    {{ 'BACKOFFICE_SERVICE_SECTION' |trans }}
                                </h6>
                                <div class="field-container {% if form_errors(form.services.task.section) is not empty %}alert-field{% endif %}">
                                    {{ form_widget(form.services.task.section) }}
                                    <span class="alert">
                                        {{ form_errors(form.services.task.section) ?: 'EMPTY_FIELD' | trans }}
                                    </span>
                                </div>
                            </div>

but this is the error I'm getting:

Neither the property "section" nor one of the methods "section()", "getsection()"/"issection()"/"hassection()" or "__call()" exist and have public access in class "Symfony\Component\Form\FormView".

Am I completely stupid and I'm missing something obvious or did I do everything wrong?

0

There are 0 best solutions below