Does Sonata admin work with self generated entity ids? - sonata-admin

Does Sonata admin work self generated entity ids? I have the following entity which uses the Uuid library to generate its own id but when I try to create a new Group using Sonata admin it gets confused and thinks I am editing an existing entity and not creating a new one.
<?php declare(strict_types=1);
namespace App\Entity;
use App\Value\StartEndTime;
use App\Exception\GroupInactiveException;
use Ramsey\Uuid\Uuid;
use Assert\Assertion;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
class Group
{
/** #var string */
private $id;
/** #var string */
private $title;
/** #var string */
private $description;
/** #var User */
private $admin;
/** #var Collection */
private $members;
/** #var Collection */
private $invites;
/** #var StartEndTime */
private $startEndTime;
/** #var StartEndTime */
private $eventStartEndTime;
public function __construct()
{
$this->id = Uuid::uuid4()->toString();
$this->members = new ArrayCollection();
$this->invites = new ArrayCollection();
}
public function getId(): string
{
return $this->id;
}
public function getTitle()
{
return $this->title;
}
public function setTitle(string $title)
{
Assertion::notEmpty($title, 'Title is not specified');
$this->title = $title;
return $this;
}
public function getDescription()
{
return $this->description;
}
public function setDescription(string $description)
{
Assertion::notEmpty($description, 'Description is not specified');
$this->description = $description;
return $this;
}
public function getStartEndTime()
{
return $this->startEndTime;
}
public function setStartEndTime(StartEndTime $startEndTime)
{
$this->startEndTime = $startEndTime;
return $this;
}
public function getEventStartEndTime()
{
return $this->eventStartEndTime;
}
public function setEventStartEndTime(StartEndTime $startEndTime)
{
$this->eventStartEndTime = $startEndTime;
return $this;
}
}

Related

Error with array collection with a one to many relation

I have a problem with a OneToMany relation and "array collection" between my entity CV and my entities, Formation, Skills and Experiences. A CV can have several formation, experiences or skills.
Even with Symfony documentation, I'm not even sure to get the issues.
Here is my Skills entity (formation and experiences are the same)
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\SkillsRepository;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource()
* #ORM\Entity(repositoryClass=SkillsRepository::class)
*/
class Skills
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $type;
/**
* #ORM\Column(type="string", length=255)
*/
private $title;
/**
* #ORM\Column(type="string", length=255)
*/
private $level;
/**
* #ORM\ManyToOne(targetEntity=Cv::class, inversedBy="id_skills")
* #ORM\JoinColumn(nullable=false)
*/
private $id_cv;
public function getId(): ?int
{
return $this->id;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(string $type): self
{
$this->type = $type;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getLevel(): ?string
{
return $this->level;
}
public function setLevel(string $level): self
{
$this->level = $level;
return $this;
}
public function getIdCv(): ?Cv
{
return $this->id_cv;
}
public function setIdCv(?Cv $id_cv): self
{
$this->id_cv = $id_cv;
return $this;
}
}
And my CV entity:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\CvRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ApiResource()
* #ORM\Entity(repositoryClass=CvRepository::class)
*/
class Cv
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity=Formation::class, mappedBy="id_cv", orphanRemoval=true)
*/
private $id_formation;
/**
* #ORM\OneToMany(targetEntity=Experiences::class, mappedBy="id_cv", orphanRemoval=true)
*/
private $id_experiences;
/**
* #ORM\OneToMany(targetEntity=Skills::class, mappedBy="id_cv", orphanRemoval=true)
*/
private $id_skills;
/**
* #ORM\Column(type="string", length=255)
*/
private $title;
/**
* #ORM\Column(type="string", length=255)
*/
private $url_perso;
/**
* #ORM\Column(type="string", length=255)
*/
private $video;
/**
* #ORM\OneToOne(targetEntity=Candidate::class, mappedBy="id_cv", cascade={"persist", "remove"})
*/
private $id_candidate;
public function __construct()
{
$this->id_formation = new ArrayCollection();
$this->id_experiences = new ArrayCollection();
$this->id_skills = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
/**
* #return Collection|Formation[]
*/
public function getIdFormation(): Collection
{
return $this->id_formation;
}
public function addIdFormation(Formation $id_cv): self
{
if (!$this->id_formation->contains($id_cv)) {
$this->id_formation[] = $id_cv;
$id_cv->setIdCv($this);
}
return $this;
}
public function removeIdFormation(Formation $id_cv): self
{
if ($this->id_formation->removeElement($id_cv)) {
// set the owning side to null (unless already changed)
if ($id_cv->getIdCv() === $this) {
$id_cv->setIdCv(null);
}
}
return $this;
}
/**
* #return Collection|Experiences[]
*/
public function getIdExperiences(): Collection
{
return $this->id_experiences;
}
public function addIdExperience(Experiences $idExperience): self
{
if (!$this->id_experiences->contains($idExperience)) {
$this->id_experiences[] = $idExperience;
$idExperience->setIdCv($this);
}
return $this;
}
public function removeIdExperience(Experiences $idExperience): self
{
if ($this->id_experiences->removeElement($idExperience)) {
// set the owning side to null (unless already changed)
if ($idExperience->getIdCv() === $this) {
$idExperience->setIdCv(null);
}
}
return $this;
}
/**
* #return Collection|Skills[]
*/
public function getIdSkills(): Collection
{
return $this->id_skills;
}
public function addIdSkill(Skills $idSkill): self
{
if (!$this->id_skills->contains($idSkill)) {
$this->id_skills[] = $idSkill;
$idSkill->setIdCv($this);
}
return $this;
}
public function removeIdSkill(Skills $idSkill): self
{
if ($this->id_skills->removeElement($idSkill)) {
// set the owning side to null (unless already changed)
if ($idSkill->getIdCv() === $this) {
$idSkill->setIdCv(null);
}
}
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getUrlPerso(): ?string
{
return $this->url_perso;
}
public function setUrlPerso(string $url_perso): self
{
$this->url_perso = $url_perso;
return $this;
}
public function getVideo(): ?string
{
return $this->video;
}
public function setVideo(string $video): self
{
$this->video = $video;
return $this;
}
public function getIdCandidate(): ?Candidate
{
return $this->id_candidate;
}
public function setIdCandidate(?Candidate $id_candidate): self
{
// unset the owning side of the relation if necessary
if ($id_candidate === null && $this->id_candidate !== null) {
$this->id_candidate->setIdCv(null);
}
// set the owning side of the relation if necessary
if ($id_candidate !== null && $id_candidate->getIdCv() !== $this) {
$id_candidate->setIdCv($this);
}
$this->id_candidate = $id_candidate;
return $this;
}
}
In my CV entity, array collection and collection are underlined in red.I try to create my REST API.
When I do a post to create a CV, I have this error message:
Could not denormalize object of type
"Doctrine\Common\Collections\Collection", no supporting
normalizer found.
Do you have a clue about what's wrong?

How to solve schema update error with doctrine?

I'm having an issue on a pretty simple application made with Symfony 4.3.4
I just updated an entity and I'm trying to update my database with "doctrine:schema:update --force", but I have here an issue : An exception occurred while executing 'ALTER TABLE lead ADD content LONGTEXT DEFAULT NULL'
Second message : Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'lead ADD content LONGTEXT DEFAULT NULL' at line 1
I tried to change the name of the "content" attribute (it's the one I added), but this did not work. Do someone know why this is happening ?
Here is my Lead entity :
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\LeadRepository")
*/
class Lead
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="datetime")
*/
private $createdAt;
/**
* #ORM\Column(type="boolean")
*/
private $isAuth = false;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Formation", inversedBy="leads")
* #ORM\JoinColumn(nullable=false)
*/
private $formation;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $content;
public function __construct()
{
$this->createdAt = new \DateTime();
}
public function getId(): ?int
{
return $this->id;
}
public function getCreatedAt(): ?\DateTimeInterface
{
return $this->createdAt;
}
public function setCreatedAt(\DateTimeInterface $createdAt): self
{
$this->createdAt = $createdAt;
return $this;
}
public function getIsAuth(): ?bool
{
return $this->isAuth;
}
public function setIsAuth(bool $isAuth): self
{
$this->isAuth = $isAuth;
return $this;
}
public function getFormation(): ?Formation
{
return $this->formation;
}
public function setFormation(?Formation $formation): self
{
$this->formation = $formation;
return $this;
}
public function getContent(): ?string
{
return $this->content;
}
public function setContent(?string $content): self
{
$this->content = $content;
return $this;
}
}
"lead" seems to be a reserved keyword for MySQL, so you need to escape it with backticks as follows:
/**
* #ORM\Entity(repositoryClass="App\Repository\LeadRepository")
* #ORM\Table(name="`lead`")
*/
You need to do this for other common keywords used as field names such as "order" and "sort" too.

Symfony 4 formbuilder loop each rows from database table

I have 2 entities :
Recettes
Categories
I try to build/list a form based on each rows of the table "Recettes" and display it from a controller.
Any ideas?
=======================
FORM_START
Name1 (TypeText) | Category (ChoiceType)
Name2 (TypeText) | Category (ChoiceType)
Name3 (TypeText) | Category (ChoiceType)
[Submit button]
FORM_END
=======================
Entity RECETTES
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Recettes
*
* #ORM\Table(name="recettes", indexes={#ORM\Index(name="categorie", columns={"categorie"})})
* #ORM\Entity
*/
class Recettes
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", length=50, nullable=false)
*/
private $nom;
/**
* #var \Categories
*
* #ORM\ManyToOne(targetEntity="Categories")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="categorie", referencedColumnName="id")
* })
*/
private $categorie;
public function getId(): ?int
{
return $this->id;
}
public function getNom(): ?string
{
return $this->nom;
}
public function setNom(string $nom): self
{
$this->nom = $nom;
return $this;
}
public function getCategorie(): ?Categories
{
return $this->categorie;
}
public function setCategorie(?Categories $categorie): self
{
$this->categorie = $categorie;
return $this;
}
}
Entity CATEGORIES
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Categories
*
* #ORM\Table(name="categories")
* #ORM\Entity
*/
class Categories
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="nom", type="string", length=50, nullable=false)
*/
private $nom;
public function getId(): ?int
{
return $this->id;
}
public function getNom(): ?string
{
return $this->nom;
}
public function setNom(string $nom): self
{
$this->nom = $nom;
return $this;
}
}
In symfony/forms each Form is an EventDispatcherInterface.
You can subscribe to one of the Events your form fires 🔥
In your case you want to add fields before your form is beeing processed.
class FriendMessageFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$builder->add('activate_recette_1', ChoiceType::class);
$builder->add('activate_recette_2', ChoiceType::class);
});
}
}
You can inject your RecetteRepository via Dependency-Injection ans use the results.
Listen to the form events via:
Event-Listener
Event-Subscriber

Foreign key not stored in database using embed form in symfony 3

I have the following entities, form types and controller
Entity Client
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Client
*
* #ORM\Table(name="client")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ClientRepository")
*/
class Client
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="address", type="string", length=255)
*/
private $address;
/**
* #ORM\OneToMany(targetEntity="Contacts", mappedBy="client", cascade={"persist"})
*/
private $contacts;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Client
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set address
*
* #param string $address
*
* #return Client
*/
public function setAddress($address)
{
$this->address = $address;
return $this;
}
/**
* Get address
*
* #return string
*/
public function getAddress()
{
return $this->address;
}
/**
* Constructor
*/
public function __construct()
{
$this->contacts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add contact
*
* #param \AppBundle\Entity\Contacts $contact
*
* #return Client
*/
public function addContact(\AppBundle\Entity\Contacts $contact)
{
$this->contacts[] = $contact;
return $this;
}
/**
* Remove contact
*
* #param \AppBundle\Entity\Contacts $contact
*/
public function removeContact(\AppBundle\Entity\Contacts $contact)
{
$this->contacts->removeElement($contact);
}
/**
* Get contacts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getContacts()
{
return $this->contacts;
}
}
Contacts entity is as below
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Contacts
*
* #ORM\Table(name="contacts")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ContactsRepository")
*/
class Contacts
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="fullname", type="string", length=255)
*/
private $fullname;
/**
* #var int
*
* #ORM\Column(name="user_type", type="smallint")
*/
private $userType;
/**
* #ORM\ManyToOne(targetEntity="Client", inversedBy="contacts")
* #ORM\JoinColumn(name="client_id", referencedColumnName="id")
*/
private $client;
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set fullname
*
* #param string $fullname
*
* #return Contacts
*/
public function setFullname($fullname)
{
$this->fullname = $fullname;
return $this;
}
/**
* Get fullname
*
* #return string
*/
public function getFullname()
{
return $this->fullname;
}
/**
* Set userType
*
* #param integer $userType
*
* #return Contacts
*/
public function setUserType($userType)
{
$this->userType = $userType;
return $this;
}
/**
* Get userType
*
* #return int
*/
public function getUserType()
{
return $this->userType;
}
/**
* Set client
*
* #param \AppBundle\Entity\Client $client
*
* #return Contacts
*/
public function setClient(\AppBundle\Entity\Client $client = null)
{
$this->client = $client;
return $this;
}
/**
* Get client
*
* #return \AppBundle\Entity\Client
*/
public function getClient()
{
return $this->client;
}
}
Client form type is as below
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use AppBundle\Entity\Client;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class ClientForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, array('attr' => array('class' => 'form-control', 'placeholder' => 'Client Name')))
->add('address', TextType::class, array('attr' => array('class' => 'form-control', 'placeholder' => 'Address')))
->add('contacts', CollectionType::class, array(
// each entry in the array will be an "email" field
'entry_type' => ContactsForm::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
))
->add('save', SubmitType::class)
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Client::class,
));
}
}
Contacts form type is as below
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Contacts;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
class ContactsForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('fullname', TextType::class, array('attr' => array('class' => 'form-control', 'placeholder' => 'Full Name')))
->add('user_type', TextType::class, array('attr' => array('class' => 'form-control', 'placeholder' => 'Co-Owner'))
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => Contacts::class,
));
}
}
Finally the controller to store data in two different tables being client as main table and contacts having foreign ken as client_id from table client is as below
/
**
* #Route("/client/add", name="add_client")
*/
public function addClientAction(Request $request)
{
$client = new Client();
$form = $this->createForm(ClientForm::class, $client);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$client = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($client);
$em->flush();
$this->addFlash(
'notice',
'Client Added!'
);
return $this->redirectToRoute('homepage');
}
return $this->render('default/addClient.html.twig', array('form' => $form->createView()));
}
The problem here is the data is added in both tables but the foreign key of the added client is not stored in table contacts, the value is null
This solution seems to work for some people may be for older version of symfony
But not luck to me. How to insert the foreign id as well. Am new to symfony and I am using symfony 3.2
It seems for me like a little mess up.
I guess you should add a contact from ContactController addAction.
Than in your Contact form type add EntityType, so you can choose a client for your contact. Here is some examples: http://symfony.com/doc/current/reference/forms/types/entity.html
Or you can set client manually by simple $contact->setClient($client) before you presist.
PS: rename Contacts entity to Contact. It is a little confusing)

creating my own user entity

I wish to make my own ' user ' entity to log in the application.
what I want to know is that if it's possible and if it is possible then where should I take precaution, which points should I consider and which files I would need to modify?
You need create a userclass by implementing UserDetailsService like
#Transactional
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
MyUser details = userDao.getUser(username);
Collection<simplegrantedauthority> authorities = new ArrayList<simplegrantedauthority>();
SimpleGrantedAuthority userAuthority = new SimpleGrantedAuthority(
"ROLE_USER");
SimpleGrantedAuthority adminAuthority = new SimpleGrantedAuthority(
"ROLE_ADMIN");
if (details.getRole().equals("user"))
authorities.add(userAuthority);
else if (details.getRole().equals("admin")) {
authorities.add(userAuthority);
authorities.add(adminAuthority);
}
UserDetails user = new User(details.getUsername(),
details.getPassword(), true, true, true, true, authorities);
return user;
}
}
an then configure spring to use your customuser object... like
<authentication-manager>
<authentication-provider user-service-ref="authService">
</authentication-provider>
</authentication-manager>
Full example can be found at Spring Custom User with DAO and Entity
You could create a user service extending UserDetailsService, and then create your UserDetail object.
It would be similar to this.
Create you User class:
public class MyUserDetails implements UserDetails {
private UserEntity user;
private List<GrantedAuthority> authorities;
/**
* Constructor
*/
public MyUserDetails(UserEntity user) {
this.user = user;
this.authorities = Arrays.asList(new SimpleGrantedAuthority(user.getRole().name()));
}
/* (non-Javadoc)
* #see org.springframework.security.core.userdetails.UserDetails#getAuthorities()
*/
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
/* (non-Javadoc)
* #see org.springframework.security.core.userdetails.UserDetails#getPassword()
*/
#Override
public String getPassword() {
return user.getPassword();
}
/* (non-Javadoc)
* #see org.springframework.security.core.userdetails.UserDetails#getUsername()
*/
#Override
public String getUsername() {
return user.getEmail();
}
/* (non-Javadoc)
* #see org.springframework.security.core.userdetails.UserDetails#isAccountNonExpired()
*/
#Override
public boolean isAccountNonExpired() {
return true;
}
/* (non-Javadoc)
* #see org.springframework.security.core.userdetails.UserDetails#isAccountNonLocked()
*/
#Override
public boolean isAccountNonLocked() {
return !user.isLocked();
}
/* (non-Javadoc)
* #see org.springframework.security.core.userdetails.UserDetails#isCredentialsNonExpired()
*/
#Override
public boolean isCredentialsNonExpired() {
return !user.isExpired();
}
/* (non-Javadoc)
* #see org.springframework.security.core.userdetails.UserDetails#isEnabled()
*/
#Override
public boolean isEnabled() {
return user.isEnabled();
}
/**
* #return the user
*/
public UserEntity getUser() {
return user;
}
/**
* #param user the user to set
*/
public void setUser(UserEntity user) {
this.user = user;
}
}
Then you should create your UserDetailsService:
#Service
public class MyUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepo;
/*
* (non-Javadoc)
* #see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
*/
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserEntity user = userDao.findByEmail(username);
if (user == null) {
LOGGER.warn("User {} does not exist in our database", username);
throw new UsernameNotFoundException("User not found.");
}
return new MyUserDetails(user);
}
}
And finally you should add the configuration for Spring security to use your service:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private MyUserDetailsService userDetailsService;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new Md5PasswordEncoder());
}
}

Resources