I am using EasyAdminBundle in a PHP Symfony project. In the admin, I have a problem displaying the NumberFields latitude and longitude in the Edit and Detail view, because EasyAdmin does not display the values stored in the database, these values are rounded to only 3 decimals instead of all the decimals stored in the database.
You can see my ActionCrudController below:
<?php
namespace App\Controller\Admin;
use App\Entity\Action;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use Symfony\Component\Routing\Annotation\Route;
use EasyCorp\Bundle\EasyAdminBundle\Field\Field;
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TelephoneField;
use EasyCorp\Bundle\EasyAdminBundle\Field\UrlField;
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
use EasyCorp\Bundle\EasyAdminBundle\Field\NumberField;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
use EasyCorp\Bundle\EasyAdminBundle\Config\Action as EasyCorpAction;
use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
class ActionCrudController extends AbstractCrudController
{
public static function getEntityFqcn(): string
{
return Action::class;
}
public function configureFields(string $pageName): iterable
{
return [
IdField::new('id')->hideOnForm(),
TextField::new('name'),
TextEditorField::new('description')->hideOnIndex(),
TextareaField::new('address'),
TextField::new('city')->hideOnIndex(),
TextField::new('postal_code')->hideOnIndex(),
TextField::new('email'),
TelephoneField::new('phone'),
UrlField::new('website')->hideOnIndex(),
TextEditorField::new('opening_hours'),
NumberField::new('latitude')->hideOnIndex(),
NumberField::new('longitude')->hideOnIndex(),
TextareaField::new('public_accueilli_detail')->hideOnIndex(),
TextareaField::new('modalite_acces')->hideOnIndex(),
TextareaField::new('tarif')->hideOnIndex(),
TextField::new('slug')->hideOnIndex(),
DateTimeField::new('created_at')->onlyOnIndex(),
DateTimeField::new('updated_at')->onlyOnIndex(),
AssociationField::new('operateur')->setRequired(true),
AssociationField::new('sousthematiques'),
AssociationField::new('public_accueilli')->hideOnIndex(),
];
}
public function configureActions(Actions $actions): Actions
{
return $actions
->add(Crud::PAGE_INDEX, EasyCorpAction::DETAIL);
}
}
And you can see my Action Entity here where latitude and longitude are float:
<?php
namespace App\Entity;
use App\Repository\ActionRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=ActionRepository::class)
* @ORM\HasLifecycleCallbacks()
* @ORM\Table("action")
*/
class Action
{
use Timestamps;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $description;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $address;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $city;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $postal_code;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $email;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $phone;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $website;
/**
* @ORM\Column(type="text", nullable=true)
*/
private $opening_hours;
/**
* @ORM\Column(type="float")
*/
private $latitude;
/**
* @ORM\Column(type="float")
*/
private $longitude;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $public_accueilli_detail;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $modalite_acces;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $tarif;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $slug;
/**
* @ORM\Column(type="datetime")
*/
private $created_at;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
private $updated_at;
/**
* @ORM\ManyToOne(targetEntity=Operateur::class, inversedBy="actions")
* @ORM\JoinColumn(nullable=false)
*/
private $operateur;
/**
* @ORM\ManyToMany(targetEntity=SousThematique::class, inversedBy="actions")
*/
private $sousthematiques;
/**
* @ORM\OneToMany(targetEntity=HoraireAction::class, mappedBy="action")
*/
private $horaire_actions;
/**
* @ORM\ManyToMany(targetEntity=PublicAccueilli::class, inversedBy="actions")
*/
private $public_accueilli;
public function __construct()
{
$this->sousthematiques = new ArrayCollection();
$this->horaire_actions = new ArrayCollection();
$this->public_accueilli = new ArrayCollection();
}
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 getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): self
{
$this->description = $description;
return $this;
}
public function getAddress(): ?string
{
return $this->address;
}
public function setAddress(?string $address): self
{
$this->address = $address;
return $this;
}
public function getCity(): ?string
{
return $this->city;
}
public function setCity(?string $city): self
{
$this->city = $city;
return $this;
}
public function getPostalCode(): ?string
{
return $this->postal_code;
}
public function setPostalCode(?string $postal_code): self
{
$this->postal_code = $postal_code;
return $this;
}
public function getEmail(): ?string
{
return $this->email;
}
public function setEmail(?string $email): self
{
$this->email = $email;
return $this;
}
public function getPhone(): ?string
{
return $this->phone;
}
public function setPhone(?string $phone): self
{
$this->phone = $phone;
return $this;
}
public function getWebsite(): ?string
{
return $this->website;
}
public function setWebsite(?string $website): self
{
$this->website = $website;
return $this;
}
public function getOpeningHours(): ?string
{
return $this->opening_hours;
}
public function setOpeningHours(?string $opening_hours): self
{
$this->opening_hours = $opening_hours;
return $this;
}
public function getLatitude(): ?float
{
return $this->latitude;
}
public function setLatitude(float $latitude): self
{
$this->latitude = $latitude;
return $this;
}
public function getLongitude(): ?float
{
return $this->longitude;
}
public function setLongitude(float $longitude): self
{
$this->longitude = $longitude;
return $this;
}
public function getPublicAccueilliDetail(): ?string
{
return $this->public_accueilli_detail;
}
public function setPublicAccueilliDetail(?string $public_accueilli_detail): self
{
$this->public_accueilli_detail = $public_accueilli_detail;
return $this;
}
public function getModaliteAcces(): ?string
{
return $this->modalite_acces;
}
public function setModaliteAcces(?string $modalite_acces): self
{
$this->modalite_acces = $modalite_acces;
return $this;
}
public function getTarif(): ?string
{
return $this->tarif;
}
public function setTarif(?string $tarif): self
{
$this->tarif = $tarif;
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(?string $slug): self
{
$this->slug = $slug;
return $this;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->created_at;
}
public function setCreatedAt(\DateTimeInterface $created_at): self
{
$this->created_at = $created_at;
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updated_at;
}
public function setUpdatedAt(?\DateTimeInterface $updated_at): self
{
$this->updated_at = $updated_at;
return $this;
}
public function getOperateur(): ?Operateur
{
return $this->operateur;
}
public function setOperateur(?Operateur $operateur): self
{
$this->operateur = $operateur;
return $this;
}
/**
* @return Collection|SousThematique[]
*/
public function getSousthematiques(): Collection
{
return $this->sousthematiques;
}
public function addSousthematique(SousThematique $sousthematique): self
{
if (!$this->sousthematiques->contains($sousthematique)) {
$this->sousthematiques[] = $sousthematique;
}
return $this;
}
public function removeSousthematique(SousThematique $sousthematique): self
{
$this->sousthematiques->removeElement($sousthematique);
return $this;
}
/**
* @return Collection|HoraireAction[]
*/
public function getHoraireActions(): Collection
{
return $this->horaire_actions;
}
public function addHoraireAction(HoraireAction $horaireAction): self
{
if (!$this->horaire_actions->contains($horaireAction)) {
$this->horaire_actions[] = $horaireAction;
$horaireAction->setAction($this);
}
return $this;
}
public function removeHoraireAction(HoraireAction $horaireAction): self
{
if ($this->horaire_actions->removeElement($horaireAction)) {
// set the owning side to null (unless already changed)
if ($horaireAction->getAction() === $this) {
$horaireAction->setAction(null);
}
}
return $this;
}
/**
* @return Collection|PublicAccueilli[]
*/
public function getPublicAccueilli(): Collection
{
return $this->public_accueilli;
}
public function addPublicAccueilli(PublicAccueilli $public_accueilli): self
{
if (!$this->public_accueilli->contains($public_accueilli)) {
$this->public_accueilli[] = $public_accueilli;
}
return $this;
}
public function removePublicAccueilli(PublicAccueilli $public_accueilli): self
{
$this->public_accueilli->removeElement($public_accueilli);
return $this;
}
public function __toString()
{
return $this->name;
}
}
I have been trying several solutions like:
- Modify the latitude and longitude form fields in the ActionCrudController -->
Ex. NumberField::new('longitude')->hideOnIndex()->setNumDecimals(12),
But this is not exactly what I want because in the Detail and Edit views does not appear the exact float stored in the database. It adds 0 if a float has less than 12 decimals.
- Another possibility I tried is modifying the Action Entity:
@ORM\Column(type="float", scale=15) private $latitude;
But it is not working either.
Do you know how can I display the latitude and longitude floats with the exact number of decimals that I have in my database in the Edit and Detail views in EasyAdmin?
Do you know where I could configure the number of decimals shown in a NumberField in EasyAdmin?
Thanks in advance for your help!
Try adding precision (and the decimal type) to your Doctrine annotations?
You can choose how precise you need to be by tweaking them.
Reply to your most recent answer (regarding your DB error): You are getting this error because there is data in your database that is stored at a more accurate level (e.g. -120.923828919)
Precision = how many total digits (disregarding the decimal) Scale = how many digits after the decimal
MySQL requires that Scale <= Precision.
You just need to tweak your precision 8 would only allow for 8 numbers e.g. the maximum it could be would be 999.99999. Coordinates go from -90 to 90 for latitude and -180 to 180 for longitude, and it is up to you how far past the decimal point you really need. I have amended my values to be a little more generous.
Apologies, I cannot comment yet but could you try adding a custom form type option. I don't think this is down to EasyAdmin itself but more the NumberType field inherited from Symfony. Doc's seem to point to using the 'scale' form type option.
so maybe
If you need to add more options, just use the plural version
->setFormTypeOptions(['scale' => 8])
instead.Direct docs link to this functionality: NumberType#scale