I'm trying to get into Symfony for a project and I (sort of) have trouble figuring out how things work in Symfony. I've done these things a couple of times in Java Spring Boot before but this project needs me doing stuff in PHP and I want to learn too.
What I have basically done is create an Entity, Repository, Service and now I'm working on the controller.
I made the entity, repo and controller using make:entity (or make:controller)
The Service is supposed to wrap the repository and further abstract things.
My questions:
In the Controller I have a constructor. Is that one actually called? I need it to initialize the Service it is used in
How do I define what HTTP Request method needs to be used? I know how to specify routes, but how do I define if it is to be accessed as GET, POST, PUT, DELETE? The Symfony doc about controllers does not specify this.
I have to find this out later so I think I'll ask here: If I want to persist an item through the api, I just pass the objects as json? (For example if I'm testing with postman)
Here's my Entity:
?php
namespace App\Entity;
use App\Repository\FahrzeugRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=FahrzeugRepository::class)
*/
class Fahrzeug
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $fahrgestellnummer;
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $tueren;
/**
* @ORM\Column(type="string", length=255)
*/
private $modellbezeichnung;
/**
* @ORM\ManyToMany(targetEntity=Person::class, mappedBy="faehrt")
*/
private $gefahren_von;
/**
* @ORM\ManyToOne(targetEntity=Marke::class, inversedBy="produziert")
* @ORM\JoinColumn(nullable=false)
*/
private $stammt_von;
public function __construct()
{
$this->gefahren_von = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getFahrgestellnummer(): ?string
{
return $this->fahrgestellnummer;
}
public function setFahrgestellnummer(string $fahrgestellnummer): self
{
$this->fahrgestellnummer = $fahrgestellnummer;
return $this;
}
public function getTueren(): ?int
{
return $this->tueren;
}
public function setTueren(?int $tueren): self
{
$this->tueren = $tueren;
return $this;
}
public function getModellbezeichnung(): ?string
{
return $this->modellbezeichnung;
}
public function setModellbezeichnung(string $modellbezeichnung): self
{
$this->modellbezeichnung = $modellbezeichnung;
return $this;
}
/**
* @return Collection|Person[]
*/
public function getGefahrenVon(): Collection
{
return $this->gefahren_von;
}
public function addGefahrenVon(Person $gefahrenVon): self
{
if (!$this->gefahren_von->contains($gefahrenVon)) {
$this->gefahren_von[] = $gefahrenVon;
$gefahrenVon->addFaehrt($this);
}
return $this;
}
public function removeGefahrenVon(Person $gefahrenVon): self
{
if ($this->gefahren_von->removeElement($gefahrenVon)) {
$gefahrenVon->removeFaehrt($this);
}
return $this;
}
public function getStammtVon(): ?Marke
{
return $this->stammt_von;
}
public function setStammtVon(?Marke $stammt_von): self
{
$this->stammt_von = $stammt_von;
return $this;
}
}
My Repo:
<?php
namespace App\Repository;
use App\Entity\Fahrzeug;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method Fahrzeug|null find($id, $lockMode = null, $lockVersion = null)
* @method Fahrzeug|null findOneBy(array $criteria, array $orderBy = null)
* @method Fahrzeug[] findAll()
* @method Fahrzeug[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class FahrzeugRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Fahrzeug::class);
}
// /**
// * @return Fahrzeug[] Returns an array of Fahrzeug objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('f')
->andWhere('f.exampleField = :val')
->setParameter('val', $value)
->orderBy('f.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?Fahrzeug
{
return $this->createQueryBuilder('f')
->andWhere('f.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
My Service
<?php
namespace App\Service;
use App\Entity\Fahrzeug;
use App\Repository\FahrzeugRepository;
use Doctrine\ORM\EntityManagerInterface;
class FahrzeugService {
private FahrzeugRepository $fahrzeugRepository;
public function __construct() {
$this->injectRepository();
}
private function injectRepository() {
$this->fahrzeugRepository = $this->getDoctrine()->getManager()->getRepository(Fahrzeug::class);
}
public function findById(int $id): Fahrzeug {
return $this->fahrzeugRepository->find($id);
}
//Returns an array
public function findAll(): array
{
return $this->fahrzeugRepository->findAll();
}
public function save(Fahrzeug $fahrzeug): Fahrzeug {
$this->fahrzeugRepository->persist($fahrzeug);
//TODO: gucken ob persist reicht oder ob man eine neue instanz erzeugen muss
$this->fahrzeugRepository->flush();
return $fahrzeug;
}
//TODO UPdate - kann man das auch mittels save machen?
public function delete(Fahrzeug $fahrzeug): Fahrzeug {
/*TODO: Herausfinden was auf der anderen Seite passiert
Idealerweise wird auf der anderen Seite das Feld genullt
*/
$this->fahrzeugRepository->remove($fahrzeug);
$this->fahrzeugRepository->flush();
return $fahrzeug;
}
}
My Controller I'm working on:
<?php
namespace App\Controller;
use App\Entity\Fahrzeug;
use App\Service\FahrzeugService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class FahrzeugController extends AbstractController
{
private FahrzeugService $fahrzeugService;
//TODO wird der Controller initialisiert?
public function __construct() {
$this->fahrzeugService = new FahrzeugService();
}
#[Route('/fahrzeugIndex', name: 'fahrzeug')]
public function index(): Response
{
return $this->render('fahrzeug/index.html.twig', [
'controller_name' => 'FahrzeugController',
]);
}
#[Route('/fahrzeug/{id}', name: 'fahrzeug')]
public function findById(int $id): Fahrzeug {
return $this->fahrzeugService->findById($id);
}
#[Route('/fahrzeug', name: 'fahrzeug')]
public function findAll(): array {
return $this->fahrzeugService->findAll();
}
#[Route('/fahrzeugIndex', name: 'fahrzeug')]
public function save(Fahrzeug $fahrzeug): Fahrzeug {
return $this->fahrzeugService->save($fahrzeug);
}
public function delete(Fahrzeug $fahrzeug): Fahrzeug {
return $this->fahrzeugService->delete($fahrzeug);
}
}
CodePudding user response:
Dependency Injection in PHP/Symfony works different than in Java/Spring. If you want to inject a dependency, you have to add it to the constructor. That dependency will be automatically constructed using the dependency-injection-container built in symfony.
private FahrzeugService $fahrzeugService;
public function __construct(FahrzeugService $fahrzeugService)
{
$this->fahrzeugService = $fahrzeugService;
}
You don't have to specify a method which injects the service. It is possible to change how your class (Controller/Service/etc.) is being created, but that's not the case here.
Once that's done, you can call methods in your FahrzeugService
using
$this->fahrzeugService->[method]()
So in your case, you can use:
<?php
namespace App\Service;
use App\Entity\Fahrzeug;
use App\Repository\FahrzeugRepository;
class FahrzeugService {
private FahrzeugRepository $fahrzeugRepository;
public function __construct(FahrzeugRepository $fahrzeugRepository) {
$this->fahrzeugRepository = $fahrzeugRepository;
}
//...
}
You don't have to get the repository from the EntityManager. It is possible, but you don't have to.
For your HTTP methods. You can specify the method in your annotations. Since you are already using the new annotations, you can use
#[Route('/fahrzeugIndex', name: 'fahrzeug', methods:['GET', 'POST'])]