Symfony 4 / Sonata: Tạo một Quản trị Một-Nhiều (1N)

Chúng tôi sẽ tạo một giao diện quản trị 1N, với hai thực thể. Thực thể đầu tiên, Một, và thực thể thứ hai, Nhiều, và thiết lập một bảng điều khiển quản trị cho bảng Một, có thể ảnh hưởng đến nhiều yếu tố của bảng Nhiều. Để làm cho mọi thứ thêm phần hấp dẫn, chúng tôi sẽ thêm một số tham số bổ sung, như các trường dấu thời gian để đồng bộ ngày với một SI, và các trường chính không được gọi là ID và không tự tăng.

Sélection_086

Trong trường hợp của chúng tôi, chúng tôi có một đồng bộ với một SI yêu cầu trường dấu thời gian.
Chỉ cần tạo một trường kiểu datetime
Thêm tùy chọn ghi chú {'default': 'CURRENT_TIMESTAMP'}
Ghi chú sau sẽ tạo một trường Timestamps với giá trị mặc định được thiết lập là CURRENT_TIMESTAMP.

* @ORM\Column(type="datetime", nullable=false, options={"default": "CURRENT_TIMESTAMP"})
* @ORM\Version


Để đặt tên cho bảng một cách chính xác và tạo chỉ mục, chỉ cần thêm ghi chú sau ở đầu lớp

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"})})
*/


Để sử dụng một trường khác với 'id' mặc định, chỉ cần thêm ghi chú sau:

/**
* @ORM\Column(type="integer")
* @ORM\Id()
*/
private $numero_dossier;


Một khi mối quan hệ được tạo, cần phải xác định id sẽ được sử dụng trong việc ánh xạ. Nếu không, sẽ có lỗi như:
Tên cột id được tham chiếu cho mối quan hệ từ App\Entity\Many đến App\Entity\One không tồn tại.

Vì vậy trong thực thể 'Nhiều', bạn cần thêm mối quan hệ với id của thực thể 'Một'

/**
* @ORM\ManyToOne(targetEntity="App\Entity\One", inversedBy="Ones")
* @ORM\JoinColumn(nullable=false, name="many_id", referencedColumnName="one_id")
*/
private $many_id;


Điểm quan trọng cuối cùng; Để tránh đối tượng có tên như 'App\Entity\One:sdfsdfgsdgmlkpoufsdlkjfsdg' khi chỉnh sửa, tốt hơn hết là ghi đè phương thức __toString(), để hiển thị tên của đối tượng.
Trong thực thể, chỉ cần bao gồm một phương thức:

public function __toString()
{
       return "Nom object ".$this->getName();
}


Một khi hoàn tất, chỉ cần tiến hành di chuyển:

php bin/console make:migration
php bin/console doctrine:migrations:migrate


Nếu cần, để tái tạo kho lưu trữ từ các thực thể có sẵn chỉ cần khởi chạy lệnh sau:

php bin/console make:entity --regenerate

Các thực thể sẽ không được sửa đổi.

Sélection_092


Để kiểm tra mối quan hệ giữa các thực thể, bạn có thể chạy lệnh sau:

php bin/console doctrine:schema:validate
Sélection_091


Ở giai đoạn này, tất cả những gì chúng tôi còn phải làm là thiết lập các giao diện quản lý trong quản trị viên, và chúng tôi có thể bắt đầu phát triển xác thực giao diện người dùng.

Bước đầu tiên của giao diện quản trị viên là tạo lớp trong 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);
		}

	}

}

Trong thực thể One.php, chúng tôi cần thêm phương thức mới của chúng tôi để xử lý các sửa đổi

    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);
        }

    }

Sau đó đăng ký dịch vụ trong config/services.yaml

    admin.MaTable:
        class: App\Admin\MaTableAdmin
        arguments: [~, App\Entity\MaTable, ~]
        tags:
            - { name: sonata.admin, manager_type: orm, label: "Table MaTable" }
        public: true