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);
}
}
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'])]
Related
Strugling here trygin to integrate VichImageUploader into my EasyAdmin 3.2.
This version of EasyAdmin is letting us create custom Fields which works just fine.
In my case I am only trying to upload 1 image and push it into my DB. I set up my Easy Admin dashboard and just followed:
https://symfony.com/doc/2.x/bundles/EasyAdminBundle/integration/vichuploaderbundle.html
to hydrate my configureFields function inside my CrudController.
As in the docs, I made a imageFile field joint to a image field althogeter with seters and geters.
Inside my CrudController I use my custom field because it seems its the only way to do image uploads in this version of easyadmin.
My CrudController
namespace App\Controller\Admin;
use App\Entity\ButtonPlant;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\UrlField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
use Vich\UploaderBundle\Form\Type\VichImageType;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Field\VichImageField;
class ButtonPlantCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return ButtonPlant::class;
}
public function configureFields(string $pageName): iterable
{
$imageFile = VichImageField::new('imageFile')->setFormType(VichImageType::class);
$image = ImageField::new('image')->setBasePath('/uploads/images');
$fields = [
TextField::new('content', 'Contenu'),
/* CollectionField::new('image')
->setEntryType(ImageType::class)
->setUploadDir('public\uploads\images\buttonplants'),
ImageField::new('imageFile')->setFormType(VichImageType::class), */
AssociationField::new('stepId', 'Etape'),
AssociationField::new('nextStepId', 'Prochaine Etape' ),
AssociationField::new('finalSheetId', 'Fiche Final'),
];
if ($pageName == Crud::PAGE_INDEX || $pageName == Crud::PAGE_DETAIL) {
$fields[] = $image;
} else {
$fields[] = $imageFile;
}
return $fields;
}
My Entity Controller
namespace App\Entity;
use App\Repository\ButtonPlantRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use DateTime;
/**
* #ORM\Entity(repositoryClass=ButtonPlantRepository::class)
* #Vich\Uploadable
*/
class ButtonPlant
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $content;
/**
* #ORM\Column(type="string", length=255)
* #var string
*/
private $image;
/**
* #Vich\UploadableField(mapping="buttonplant_images", fileNameProperty="image")
* #var File
*/
private $imageFile;
/**
* #ORM\OneToOne(targetEntity=FinalSheet::class, cascade={"persist", "remove"})
*/
private $finalSheetId;
/**
* #ORM\ManyToOne(targetEntity=CoursePlant::class, inversedBy="buttonPlants")
* #ORM\JoinColumn(nullable=false)
*/
private $stepId;
/**
* #ORM\OneToOne(targetEntity=CoursePlant::class, cascade={"persist", "remove"})
*/
private $nextStepId;
/**
* #ORM\Column(type="datetime", nullable=true)
* #var \DateTime
*/
private $updatedAt;
public function getId(): ?int
{
return $this->id;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(string $content): self
{
$this->content = $content;
return $this;
}
public function getImage(): ?string
{
return $this->image;
}
public function setIamge(string $image): self
{
$this->image = $image;
return $this;
}
public function setImageFile(File $image = null)
{
$this->imageFile = $image;
// VERY IMPORTANT:
// It is required that at least one field changes if you are using Doctrine,
// otherwise the event listeners won't be called and the file is lost
if ($image) {
// if 'updatedAt' is not defined in your entity, use another property
$this->updatedAt = new \DateTime('now');
}
}
public function getImageFile()
{
return $this->imageFile;
}
public function getFinalSheetId(): ?FinalSheet
{
return $this->finalSheetId;
}
public function setFinalSheetId(?FinalSheet $finalSheetId): self
{
$this->finalSheetId = $finalSheetId;
return $this;
}
public function getStepId(): ?CoursePlant
{
return $this->stepId;
}
public function setStepId(?CoursePlant $stepId): self
{
$this->stepId = $stepId;
return $this;
}
public function getNextStepId(): ?CoursePlant
{
return $this->nextStepId;
}
public function setNextStepId(?CoursePlant $nextStepId): self
{
$this->nextStepId = $nextStepId;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(?\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
}
My custom Field
namespace EasyCorp\Bundle\EasyAdminBundle\Field;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Vich\UploaderBundle\Form\Type\VichImageType;
class VichImageField implements FieldInterface
{
use FieldTrait;
public static function new(string $propertyName, ?string $label = null)
{
return (new self())
->setProperty($propertyName)
->setTemplatePath('')
->setLabel($label)
->setFormType(VichImageType::class);
}
}
And my error is
Could not determine access type for property "image" in class "App\Entity\ButtonPlant".
Thanks in advance for any help
I solved my problem deleting the field "image" and creating it back but this time is allowed to be null.
Hopefully it can be useful for anyone
First of all, I apologize for my basic use of english, I hope you can understand me.
I'm doing a deployment of a project, the development was on Symfony 5.1, using easyadmin-bundle 3.1, and vich/uploader-bundle 1.15. On my localhost that works great, but when I move to production, on my dashboard, can't 'Create New' or 'Edit' in any entity who has images inside, it throw me this error.
An error has occurred resolving the options of the form "Vich\UploaderBundle\Form\Type\VichImageType": The options "upload_dir", "upload_filename" do not exist.
https://i.ibb.co/gWRjPLm/Screenshot-2020-11-20-An-error-has-occurred-resolving-the-options-of-the-form-Vich-Uploader-Bundle-F.png
The only place I find upload_dir, is inside vendor folder.
https://i.ibb.co/VHw39z5/Screenshot-2020-11-20-Symfony-Profiler.png
My entity
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* #ORM\Entity(repositoryClass=ColoresRepository::class)
* #Vich\Uploadable()
*/
class Colores
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=30)
*/
private $nombre;
/**
* #ORM\Column(type="string", length=100)
*/
private $thumbnail;
/**
* #Vich\UploadableField(mapping="colores", fileNameProperty="thumbnail")
*/
private $thumbnailFile;
/**
* #ORM\Column(type="datetime")
*/
private $updatedAt;
public function __construct()
{
$this->updatedAt = new \DateTime();
}
/**
* #return mixed
*/
public function getThumbnailFile()
{
return $this->thumbnailFile;
}
/**
* #param mixed $thumbnailFile
*/
public function setThumbnailFile($thumbnailFile): void
{
$this->thumbnailFile = $thumbnailFile;
if($thumbnailFile) {
$this->updatedAt = new \DateTime();
}
}
/**
* #return mixed
*/
public function getThumbnail()
{
return $this->thumbnail;
}
/**
* #param mixed $thumbnail
*/
public function setThumbnail($thumbnail): void
{
$this->thumbnail = $thumbnail;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeInterface $updatedAt): self
{
$this->updatedAt = $updatedAt;
return $this;
}
public function getId(): ?int
{
return $this->id;
}
public function getNombre(): ?string
{
return $this->nombre;
}
public function setNombre(string $nombre): self
{
$this->nombre = $nombre;
return $this;
}
public function __toString()
{
return $this->nombre;
}
}
My Dashboard
<?php
namespace App\Controller\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Router\CrudUrlGenerator;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\Colores;
class DashboardController extends AbstractDashboardController
{
/**
* #Route("admin", name="admin")
*/
public function index(): Response
{
$routeBuilder = $this->get(CrudUrlGenerator::class)->build();
return $this->redirect($routeBuilder->setController(ColoresCrudController::class)->generateUrl());
}
public function configureDashboard(): Dashboard
{
return Dashboard::new()
->setTitle('Test Site');
}
public function configureMenuItems(): iterable
{
yield MenuItem::section('DESTACADOS');
yield MenuItem::linkToCrud('Colores', 'fa fa-paint-brush', Colores::class);
}
My Crud controller
<?php
namespace App\Controller\Admin;
use App\Entity\Colores;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use Vich\UploaderBundle\Form\Type\VichImageType;
class ColoresCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Colores::class;
}
public function configureFields(string $pageName): iterable
{
return [
TextField::new('nombre'),
ImageField::new('thumbnailFile')
->setFormType(VichImageType::class)->onlyOnForms(),
ImageField::new('thumbnail')
->setBasePath('/images/colores')->hideOnForm()
];
}
}
vich_uploader.yaml
vich_uploader:
db_driver: orm
mappings:
colores:
uri_prefix: /images/colores
upload_destination: '%kernel.project_dir%/public/images/colores'
namer: Vich\UploaderBundle\Naming\UniqidNamer
Using setFormType is an "undocumented hack"
There is an issue with the v3.1.8 and the ImageField.
You can try this syntax :
$filename = ImageField::new('filename', 'File')
->setBasePath('uploads/contact_message')
->setUploadDir('public/uploads/contact_message/');
If it doesn't work you can roll back to v.3.1.7 (force the version in your composer.json) and using the old syntax with 2 field ( the file and the filename)
$avatar = ImageField::new('avatar')->setBasePath('uploads/images/users')->setLabel('Photo');
$avatarFile = ImageField::new('avatarFile')->setFormType(VichImageType::class);
if (Crud::PAGE_INDEX === $pageName) {
return [ $avatar];
} elseif (Crud::PAGE_EDIT=== $pageName) {
return [$avatarFile];
You can create your own Custom Field (see https://symfony.com/doc/current/bundles/EasyAdminBundle/fields.html#creating-custom-fields) like this :
namespace App\Admin\Field;
use EasyCorp\Bundle\EasyAdminBundle\Contracts\Field\FieldInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\FieldTrait;
use Vich\UploaderBundle\Form\Type\VichImageType;
class VichImageField implements FieldInterface
{
use FieldTrait;
public static function new(string $propertyName, ?string $label = null): self
{
return (new self())
->setProperty($propertyName)
->setLabel($label)
->setFormType(VichImageType::class)
->setCustomOption('image_uri', null)
->setCustomOption('download_uri', null)
;
}
public function setImageUri($imageUri): self
{
$this->setCustomOption('image_uri', $imageUri);
return $this;
}
public function setDownloadUri($downloadUri): self
{
$this->setCustomOption('download_uri', $downloadUri);
return $this;
}
}
And the use it in your crud controller configureFileds method :
VichImageField::new('avatarFile', 'Avatar')
->setDownloadUri('public/' . $this->getParameter('app.path.user_avatars'))
->setImageUri($this->getParameter('app.path.user_avatars'))
,
It works with the last EasyAdminBundle > v3.1.7
I was doing a tutorial about Symfony (2018) on youtube:
https://www.youtube.com/watch?v=kfiKn5c9l84&ab_channel=TraversyMedia
when I enter the route ../articles/save, it should save my data in the database table. The first time, it worked. However, when I changed the data to second article and tried to save, I get this error about foreach() (see image):
I don't know the reason for that or how to disable the Cache.. (or ChachedReader)..
this is my Code to save an article:
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Entity\Article;
class ArticleController extends AbstractController {
/**
* #Route("/article", name="test_index")
* #Method({"GET"})
*/
public function index() {
$articles = ["Article1", "Article2"];
return $this->render('./articles/index.html.twig', array('articles' => $articles));
}
/**
* #Route("/article/save")
*/
public function save() {
$entityManager = $this->getDoctrine()->getManager();
$article = new Article();
$article->setTitle("Article Two");
$article->setBody("This is the body for article two");
$entityManager->persist($article);
$entityManager->flush();
return new Response("Saved an article with the id of".$article->getId());
}
}
edit:this is my article entity:
<?php
namespace App\Entity;
use App\Repository\ArticleRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass=ArticleRepository::class)
*/
class Article
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="text", length=100)
*/
private $title;
/**
* #ORM\Column(type="text")
*/
private $body;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle($title): ?string
{
$this->title = $title;
return $this->title;
}
public function getBody(): ?string
{
return $this->body;
}
public function setBody(string $body): self
{
$this->body = $body;
return $this;
}
}
I have a constructor and route in my custom ProfileController
private $userManager;
public function __construct(UserManagerInterface $userManager)
{
$this->userManager = $userManager;
}
/**
* #Route("/profile/bookings", name="profile_bookings")
*/
public function bookings()
{
$user = $this->getUser();
return $this->render('profile/bookings/bookings.html.twig', array('user'=>$user));
}
And in my template I reference
{{ user.first_name }}
But I get the error:
HTTP 500 Internal Server Error
Neither the property "first_name" nor one of the methods "first_name()", "getfirst_name()"/"isfirst_name()"/"hasfirst_name()" or "__call()" exist and have public access in class "App\Entity\User".
How do I get the user info from db and display in sub pages of profile?
Edit: User Entity ...
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
/**
* #ORM\Entity
* #ORM\Table(name="`user`")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
protected $id;
/**
* #ORM\Column(type="string", length=190)
*/
private $first_name;
/**
* #ORM\Column(type="string", length=190)
*/
private $last_name;
/**
* #ORM\Column(type="string", length=190, nullable=true)
*/
private $phone_number;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $profile_height;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $profile_weight;
/**
* #ORM\Column(type="date", nullable=true)
*/
private $profile_dob;
/**
* #ORM\Column(type="string", length=190, nullable=true)
*/
private $profile_gender;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Booking", mappedBy="user")
*/
private $bookings;
public function __construct()
{
parent::__construct();
$this->bookings = new ArrayCollection();
}
/**
* Overridde setEmail method so that username is now optional
*
* #param string $email
* #return User
*/
public function setEmail($email)
{
$this->setUsername($email);
return parent::setEmail($email);
}
public function getFirstName()
{
return $this->first_name;
}
public function setFirstName($first_name)
{
$this->first_name = $first_name;
}
public function getLastName()
{
return $this->last_name;
}
public function setLastName($last_name)
{
$this->last_name = $last_name;
}
public function getPhoneNumber(): ?string
{
return $this->phone_number;
}
public function setPhoneNumber(string $phone_number): self
{
$this->phone_number = $phone_number;
return $this;
}
public function getProfileHeight(): ?int
{
return $this->profile_height;
}
public function setProfileHeight(?int $profile_height): self
{
$this->profile_height = $profile_height;
return $this;
}
public function getProfileDob(): ?\DateTimeInterface
{
return $this->profile_dob;
}
public function setProfileDob(?\DateTimeInterface $profile_dob): self
{
$this->profile_dob = $profile_dob;
return $this;
}
public function getProfileWeight(): ?int
{
return $this->profile_weight;
}
public function setProfileWeight(?int $profile_weight): self
{
$this->profile_weight = $profile_weight;
return $this;
}
public function getProfileGender(): ?string
{
return $this->profile_gender;
}
public function setProfileGender(?string $profile_gender): self
{
$this->profile_gender = $profile_gender;
return $this;
}
/**
* #return Collection|Booking[]
*/
public function getBookings(): Collection
{
return $this->bookings;
}
public function addBooking(Booking $booking): self
{
if (!$this->bookings->contains($booking)) {
$this->bookings[] = $booking;
$booking->setUser($this);
}
return $this;
}
public function removeBooking(Booking $booking): self
{
if ($this->bookings->contains($booking)) {
$this->bookings->removeElement($booking);
// set the owning side to null (unless already changed)
if ($booking->getUser() === $this) {
$booking->setUser(null);
}
}
return $this;
}
}
Thanks.
#Franck Gamess is right but you can also get rid of the get.
If you write {{ user.firstName }}, twig will associate that to your method getFirstName() automatically.
I don't know why you write your properties with snake_case but you could change it to camelCase and access your properties via their "real" name.
Just use in your twig template:
{{ user.getFirstName }}
It works fine. Normally what Twig does is quite simple on the PHP Layer:
check if user is an array and first_name a valid element;
if not, and if user is an object, check that first_name is a valid property;
if not, and if user is an object, check that first_name is a valid method (even if first_name is the constructor - use __construct() instead);
if not, and if user is an object, check that getfirst_name is a valid method;
if not, and if user is an object, check that isfirst_name is a valid method;
if not, and if user is an object, check that hasfirst_name is a valid method;
if not, return a null value.
See Twig variables.
By the way you should follow the Symfony Coding Standard for your variable, because it can be difficult for twig to find value of properties written in snake_case.
I don't think you should construct the UserManagerInterface in your controller. Also, like Franck says, use the coding standard if you can, it will save a lot of time and frustration in the future!
Here is the controller I use in a Symfony 4 project:
namespace App\Controller;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
/**
* #Route("/profile/bookings", name="profile_bookings")
*/
public function bookings()
{
$user = $this->getUser();
if (!is_object($user) || !$user instanceof UserInterface) {
throw new AccessDeniedException('This user does not have access to this section.');
}
return $this->render('profile/bookings/bookings.html.twig', array(
'user' => $user,
));
}
}
I have a custom repository in my Symfony's project and I want use like a search tool. My project' structure is the following:
P.D. UPDATED Question and code
-Manager:
* BaseManager.php
* MyEntityManager.php
-Repository:
* BaseRepository.php
* MyEntityRepository.php
Well, I want access to my custom repository and use the following method findByTitle, which method should return an array with objects which description field be similar. I put a simple print (var_dump of the term entered) inside of my function to see if my browser shows it, but it isn't showed yet...
My BaseManager:
<?php
namespace AppBundle\Manager;
use AppBundle\Repository\BaseRepository;
class BaseManager
{
/**
* #var BaseRepository
*/
protected $repo;
/**
* #param BaseRepository $repo
*/
public function __construct(BaseRepository $repo)
{
$this->repo = $repo;
}
/**
* #param $model
* #return bool
*/
public function create($model)
{
return $this->repo->create($model);
}
/**
* #param CrudModel $model
* #return bool
*/
public function update($model)
{
return $this->repo->save($model);
}
/**
* #param CrudModel $model
* #return bool
*/
public function delete($model)
{
return $this->repo->delete($model);
}
/**
* #param $id
* #return null|object
*/
public function getOneById($id)
{
return $this->repo->findOneById($id);
}
/**
* #return array
*/
public function all()
{
return $this->repo->all();
}
}
MyEntityManager:
<?php
namespace AppBundle\Manager;
use AppBundle\Repository\MyEntityRepository;
use AppBundle\Entity\MyEntity;
/**
* Class MyEntityManager
* #package AppBundle\Manager
*/
class MyEntityManager extends BaseManager{
public function findByTitle($title){
echo '<h1>flux of code here</h1>';
return $this->repo->findByTitle($title);
}
public function findSimilars($term){
echo '<h1>flux of code here</h1>';
return $this->repo->findSimilars($term);
}
}
BaseRepository:
<?php
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
abstract class BaseRepository extends EntityRepository
{
public function create($model, $autoFlush = true)
{
return $this->insert($model,$autoFlush);
}
public function save($model, $autoFlush = true)
{
return $this->insert($model,$autoFlush);
}
public function delete($model)
{
try{
$this->getEntityManager()->remove($model);
$this->getEntityManager()->flush();
return true;
}catch (\Exception $e){
echo $e->getMessage();
}
}
public function findOneById($id)
{
return $this->findOneBy(array('id' => $id));
}
public function all()
{
return $this->findAll();
}
private function insert($model, $autoFlush = true)
{
$this->getEntityManager()->persist($model);
if ($autoFlush) {
$this->getEntityManager()->flush();
return true;
}
}
}
MyEntityRepository:
<?php
namespace AppBundle\Repository;
use Doctrine\ORM\EntityRepository;
/**
* Class MyEntityRepository
* #package AppBundle\Repository
*/
class MyEntityRepository extends BaseRepository{
private function findById($id){
$query = $this->createQueryBuilder('myentity')
->where('myentity.id = :id')
->setParameter('id', $id)
->getQuery();
$myentity = $query->getResult();
return $myentity;
}
private function findByTitle($term){
echo '<h1>';
var_dump($term);
echo '</h1>',
$query = $this->createQueryBuilder('myentity')
->andwhere('myentity.description = :description')
->setParameter('description', $term)
->getQuery();
$myentity = $query->getResult();
return $myentity;
}
}
The beginning of MyEntity:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* #ORM\Table(name="myentity")
* #ORM\Entity
* #ORM\Entity(repositoryClass="AppBundle\Repository\MyEntityRepository")
*/
class MyEntity {
......
My services.yml:
parameters:
app.myentity.repository.class: AppBundle\Repository\MyEntityRepository
app.myentity.manager.class: AppBundle\Manager\MyEntityManager
services:
app.myentity.repository:
class: %app.myentity.repository.class%
public: true
factory_service: doctrine.orm.entity_manager
factory_method: getRepository
arguments: [ AppBundle\Entity\MyEntity ]
app.myentity.manager:
class: %app.myentity.manager.class%
arguments: [#app.myentity.repository]
And I'm calling my service in the following way:
public function searchAction(Request $request, $term){
$manager = $this->get('app.myentity.manager');
$result = $manager->findByTitle($term);
echo '<h5>';
var_dump($result);
echo '</h5>';
....
}
Just a guess, as your question is far from being clear (esp. the last paragraph): did you only register the service, or did you also tell Symfony to use the repository for the entity (presumably MyEntity)? For instance, using annotations, you’d need something like this:
#ORM\Entity(repositoryClass="The\RepositoryClass")
The problem was that I declared my function as private instead of public
private function findByTitle($term){
instead of
public function findByTitle($term){