Nous allons créer une une interface d’administration 1N, avec deux entités. La première One, et la seconde Many, et faire un panel d’admin pour la table One, qui pourras affected plusieurs éléments de la table Many. Pour corser le truc, on s’ajoute quelques paramètres additionnels, tel que des champs timestamps pour une date de synchro avec un SI, et des champs primary qui ne s’appellent pas ID et qui ne sont pas auto incrémentés.
Dans notre cas, nous avons une synchro avec un SI qui nécessite un champs timestamps.
Il suffit juste de créer un champs de type datetime
Ajouter l’annonation options={« default »: « CURRENT_TIMESTAMP »}
L’annotation suivante créera un champs Timepstamps avec en default CURRENT_TIMESTAMP.
* @ORM\Column(type="datetime", nullable=false, options={"default": "CURRENT_TIMESTAMP"})
* @ORM\Version
Pour nommer correctement la table et créer les index, il suffit de rajouter l’annotation suivante en entête de classe
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Table;
use Doctrine\ORM\Mapping\Id;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Index;
/**
* @ORM\Entity(repositoryClass="App\Repository\WcoconRepository")
* @Table(name="table_name",indexes={@Index(name="PRIMARY", columns={"champs1", "champs2"})})
*/
Pour utiliser un autre champs que « id » mis par défaut, il faut juste ajouter l’annotation suivante :
/**
* @ORM\Column(type="integer")
* @ORM\Id()
*/
private $numero_dossier;
Une fois la relation faite, il faut préciser l’id qui sera utilisé dans le mapping. sinon on aura une erreur du type :
Column name id
referenced for relation from App\Entity\Many towards App\Entity\One does not exist.
Donc dans l’entité ‘Many’, il faut ajouter la relation avec l’id de l’entité ‘One’
/**
* @ORM\ManyToOne(targetEntity="App\Entity\One", inversedBy="Ones")
* @ORM\JoinColumn(nullable=false, name="many_id", referencedColumnName="one_id")
*/
private $many_id;
Dernier point qui a son importance; Pour éviter que l’objet ait le un nom du type « App\Entity\One:sdfsdfgsdgmlkpoufsdlkjfsdg » lors de l’édition, il est préférable de surcharger la méthode __toString(), pour afficher le nom de l’objet.
Dans l’entity il suffit d’inclure une méthode :
public function __toString()
{
return "Nom object ".$this->getName();
}
Une fois fait, il suffit de faire la migration :
php bin/console make:migration
php bin/console doctrine:migrations:migrate
Au besoin pour régénérer le repository à partir des entités disponibles il suffit de lancer cette commande :
php bin/console make:entity --regenerate
Les entités ne seront pas modifiés.
Pour tester la relations entre les entités, on peux passer la commande suivante :
php bin/console doctrine:schema:validate
A ce stade, il ne nous reste plus qu’a mettre en place les interfaces de gestion dans l’admin et on pourras commencer à développer l’authentification en front.
Première étape de l’interface d’admin est de créer la classe dans src/Admin/TableAdmin.php
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Sonata\AdminBundle\Form\Type\ModelAutocompleteType;
use Sonata\AdminBundle\Form\Type\ModelType;
use Sonata\AdminBundle\Form\Type\ModelListType;
use Sonata\Form\Type\CollectionType;
class OneAdmin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper->tab('General');
$formMapper->with('Parametres', ['class' => 'col-md-4']);
$formMapper->add('name', TextType::class, ['required' => false, 'label'=>'Site internet','attr' => ['placeholder' => '']]);
$formMapper->end()
$formMapper->with('Parametres', ['class' => 'col-md-8']);
$formMapper->add('nomduchampsArrayCollection', EntityType::class, [
'class' => 'App\Entity\Many',
'choice_label' => 'nom_du_champs_autre_table',
'label' => 'champs liste',
'multiple' => true,
//'expanded' => true,
]);
$formMapper->end()
$formMapper->end('General');
}
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper->add('name');
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper->addIdentifier('name', null, ['label' => 'Nom']);
}
public function prePersist($object)
{
$this->preUpdate($object);
}
public function preUpdate($object)
{
$mapping=$object->getManys()->getMapping();
$currentManys=$this->createQuery()->getQueryBuilder()->getQuery()->getEntityManager()->getRepository($mapping["targetEntity"])
->findBy([$mapping["mappedBy"]=>$this->id($object)]);
$object->setMany($object->getManys(),$currentManys);
}
public function setMany($collections,$currentManys)
{
foreach ($currentCollections as $w)
{
if(!$collections->contains($w)){
$w->setCollectionID(null);
}
}
$this->collections= new ArrayCollection();
foreach ($collections as $collection) {
$this->addCollections($collections);
}
}
}
Dans l’entity One.php il faut rajouter notre nouvelle méthode pour gérer les modifications
public function setMany($manys,$current)
{
foreach ($current as $w) {
if(!$manys->contains($w)){
$w->setManyField(null);
}
}
$this->manys = new ArrayCollection();
foreach ($manys as $m) {
$this->addMany($m);
}
}
Il faut ensuite enregistrer le service dans config/sercices.yaml
admin.MaTable:
class: App\Admin\MaTableAdmin
arguments: [~, App\Entity\MaTable, ~]
tags:
- { name: sonata.admin, manager_type: orm, label: "Table MaTable" }
public: true