Chúng ta sẽ xem cách khai thác kiểu trường Jsonb từ PostgreSQL trong một giao diện được tạo bởi Sonata.
Chúng ta bắt đầu với giả định rằng bạn đã nắm vững các khái niệm cơ bản của Symfony, Sonata, và PostgreSQL.
Đầu tiên, hãy tạo một bảng đơn giản trong PostgreSQL sẽ chứa trường Jsonb.

CREATE SEQUENCE public.table1_id_seq;
CREATE TABLE public.table1 (
id integer DEFAULT nextval('public.table1_id_seq'::regclass) NOT NULL,
var1 character varying(250),
var2 jsonb
);
ALTER TABLE ONLY public.table1
ADD CONSTRAINT table1_pkey PRIMARY KEY (id);
Sau đó, tạo entity và giao diện quản trị của nó
php bin/console doctrine:mapping:import "App\Entity" annotation --path=src/Entity
php bin/console make:entity --regenerate App
php bin/console make:sonata:admin App/Entity/Table1
Chúng ta nhận thấy kiểu trường trong entity của mình
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Table1
*
* @ORM\Table(name="table1")
* @ORM\Entity
*/
class Table1
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="SEQUENCE")
* @ORM\SequenceGenerator(sequenceName="table1_id_seq", allocationSize=1, initialValue=1)
*/
private $id;
/**
* @var string|null
*
* @ORM\Column(name="var1", type="string", length=250, nullable=true)
*/
private $var1;
/**
* @var json|null
*
* @ORM\Column(name="var2", type="json", nullable=true)
*/
private $var2;
public function getId(): ?int
{
return $this->id;
}
public function getVar1(): ?string
{
return $this->var1;
}
public function setVar1(?string $var1): self
{
$this->var1 = $var1;
return $this;
}
public function getVar2(): ?array
{
return $this->var2;
}
public function setVar2(?array $var2): self
{
$this->var2 = $var2;
return $this;
}
}
Và giao diện quản trị được tạo của chúng ta trong định dạng đơn giản nhất
<?php
declare(strict_types=1);
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
final class Table1Admin extends AbstractAdmin
{
protected function configureDatagridFilters(DatagridMapper $datagridMapper): void
{
$datagridMapper
->add('id')
->add('var1')
->add('var2')
;
}
protected function configureListFields(ListMapper $listMapper): void
{
$listMapper
->add('id')
->add('var1')
->add('var2')
->add('_action', null, [
'actions' => [
'show' => [],
'edit' => [],
'delete' => [],
],
]);
}
protected function configureFormFields(FormMapper $formMapper): void
{
$formMapper
->add('id')
->add('var1')
->add('var2')
;
}
protected function configureShowFields(ShowMapper $showMapper): void
{
$showMapper
->add('id')
->add('var1')
->add('var2')
;
}
}
Mục tiêu của chúng ta bây giờ là tạo một cấu trúc form lồng để quản lý dữ liệu của chúng ta trong json.
Để làm điều này, chúng ta sẽ sử dụng bộ sưu tập của Symfony.
Các bước như sau: chúng ta sẽ tạo một form sẽ được tích hợp vào trường. Nó sẽ có nút thêm/bớt để thêm mục vào bộ sưu tập của chúng ta.
Chúng ta sau đó sẽ liên kết form của mình với trường "var2".
Chúng ta tạo form của mình trong thư mục Form của src.
<?php #src/Form/fieldvar2.php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type as FormType;
class fieldvar2 extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('var2_titre', FormType\TextType::class, [
'label' => 'Var2 titre',
])
->add('var2_valeur', FormType\TextType::class, [
'label' => 'var2 valeur',
]);
}
public function configureOptions(OptionsResolver $resolver)
{
}
}
?>
Sau đó, chúng ta cần liên kết form này với trường của mình.
use Symfony\Component\Form\Extension\Core\Type as FormType;
use App\Form\fieldvar2;
final class Table1Admin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $formMapper): void
{
$formMapper
//->add('id') #on supprime le champs id puisqu'il est auto incrémenté
->add('var1')
->add('var2', FormType\CollectionType::class, [
'allow_add' => true,
'allow_delete' => true,
'entry_type' => 'App\\Form\\fieldvar2',
'label' => 'Var jsonb',
])
;
}

Bây giờ chúng ta sẽ xem cách chúng ta có thể có sự lồng ghép của các form trong form của mình. Nói cách khác, "bộ sưu tập lồng".
Và để làm điều này, chúng ta sẽ phải sử dụng thành phần Collection của Sonata vì đó là thành phần duy nhất sẽ hoạt động với nhiều lớp lồng (theo lý thuyết, vô hạn).
Chúng ta sẽ thêm tham chiếu đến Sonata\AdminBundle\Form\Type\CollectionType, tạo một form thứ hai và triển khai nó trong form đầu tiên của chúng ta.
<?php #src/Form/fieldvar2valeur.php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type as FormType;
class fieldvar2valeur extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('valeurs_multiples', FormType\TextType::class, [
'label' => 'Netsted 2 val',
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'allow_extra_fields' => true,
'allow_add' => true,
]);
}
}
?>
Triển khai bộ sưu tập cấp độ 2 của chúng ta
<?php #src/Form/fieldvar2.php
namespace App\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type as FormType;
use App\Form\fieldvar2valeur;
use Sonata\AdminBundle\Form\Type\CollectionType;
class fieldvar2 extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('var2_titre', FormType\TextType::class, [
'label' => 'Var2 titre',
])
->add('var2_valeur', CollectionType::class, [
'allow_add' => true,
'allow_delete' => true,
'entry_type' => 'App\\Form\\fieldvar2valeur',
'label' => 'Data Nested 2',
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'allow_extra_fields' => true,
'allow_add' => true,
]);
}
}
?>
Và tất cả những gì còn lại là chỉnh sửa cấu hình của bộ sưu tập của chúng ta để sử dụng thành phần SonataAdmin
<?php
declare(strict_types=1);
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use App\Form\fieldvar2;
use Sonata\AdminBundle\Form\Type\CollectionType;
final class Table1Admin extends AbstractAdmin
{
protected function configureDatagridFilters(DatagridMapper $datagridMapper): void
{
$datagridMapper
->add('id')
->add('var1')
->add('var2')
;
}
protected function configureListFields(ListMapper $listMapper): void
{
$listMapper
->add('id')
->add('var1')
->add('var2')
->add('_action', null, [
'actions' => [
'show' => [],
'edit' => [],
'delete' => [],
],
]);
}
protected function configureFormFields(FormMapper $formMapper): void
{
$formMapper
//->add('id')
->add('var1')
->add('var2', CollectionType::class, [
'allow_add' => true,
'allow_delete' => true,
'entry_type' => 'App\\Form\\fieldvar2',
'label' => 'Var jsonb',
])
;
}
protected function configureShowFields(ShowMapper $showMapper): void
{
$showMapper
->add('id')
->add('var1')
->add('var2')
;
}
}
Đây là cách nó trông như thế nào
