Идея заключается в следующем. В таблице «драйвер» у меня есть поля, которые описывают «драйвер», но мне нужно хранить другой набор полей около 100, которые мне не нужны, чтобы быть столбцами таблицы. Поэтому я решил хранить их в поле Jsonb. Мне нужно иметь возможность работать с этими полями как с полями модели, но они должны автоматически сохраняться в одном поле jsonb … и когда я выбираю из таблицы, мне нужно, чтобы это поле отображалось как другие поля из таблицы.
Я проверил документацию о конвертерах и нашел конвертер PgJson. Поэтому я думаю, что это правильный инструмент для решения этой проблемы, но мне пока не удалось правильно все настроить.
Я попытался зарегистрировать поле «testinfo» как тип «extrainfo», который зарегистрирован как конвертер в SessionBuilder, но безуспешно. Методы fromPg и toPG не вызываются. Здесь я показываю примеры из файлов моего проекта.
composer.json
...
"require": {
"php": ">=7.0.0",
...
"pomm-project/pomm-bundle": "^2.3",
"sensio/distribution-bundle": "^5.0.19",
"sensio/framework-extra-bundle": "^3.0.2",
...
"symfony/symfony": "3.3.6",
...
"vibby/pomm-project-fos-user-bundle": "dev-master"},
...
CREATE TABLE public.driver
(
driver_id bigint NOT NULL DEFAULT nextval('driver_driver_id_seq'::regclass),
account_id integer NOT NULL,
infodata jsonb, -- large number of fields,...
weight jsonb, -- weights for fields that are not in jsonb field
ssn character varying,
signature character varying
-- ...
)
config.yml
pomm:
configuration:
driversdb:
dsn: "pgsql://%db_user2%:%db_password2%@%db_host2%:%db_port2%/%db_name2%"#session_builder: "pomm.session_builder"pomm:default: true
session_builder: 'AppBundle\Model\Driversdb\SessionBuilder'
services.yml
...
drivertojson:
class: AppBundle\Service\DriverToJson
tags:
- { name: pomm.model, converter: pomm.model }
AppBundle\Model\Driversdb\SessionBuilder:
autowire: true
...
/src/AppBundle/Model/Driversdb/SessionBuilder.php
namespace AppBundle\Model\Driversdb;
use AppBundle\Service\DriverToJson; //Exact Copy of Pomm PgJson converter.
use PommProject\Foundation\Converter\PgJson;
use PommProject\Foundation\Session\Session;
use PommProject\ModelManager\SessionBuilder as BaseSessionBuilder;
class SessionBuilder extends BaseSessionBuilder
{
protected function postConfigure(Session $session) {
parent::postConfigure($session);
$session
->getPoolerForType('converter')
->getConverterHolder()
->registerConverter('extrainfo', new DriverToJson(), ['infodata', 'public.driver.infodata']) // register Jsonb converter
->addTypeToConverter('extrainfo', 'extrainfo', false) // convert a domain of point
;
}
}
/src/AppBundle/Model/Driversdb/PublicSchema/Driver.php
namespace AppBundle\Model\Driversdb\PublicSchema;
use PommProject\ModelManager\Model\FlexibleEntity;
/**
* Driver
* Flexible entity for relation
* public.driver
* @see FlexibleEntity
*/
class Driver extends FlexibleEntity
{
public $keyForId = 'driver_id';
public function getId() {
return $this->get($this->keyForId);
}
public function __toString() {
return $this->getSsn();
}
private $driver_id;
private $account_id;
private $infodata;
private $weight;
private $ssn;
private $signature;
//...
private $testinfo;
public function getTestinfo() {
if ($this->has('testinfo')) {
return $this->get('testinfo');
} else {
return '';
}
}
public function getDriverId() {
if ($this->has('driver_id')) {
return $this->get('driver_id');
} else {
return '';
}
}
public function getAccountId() {
if ($this->has('account_id')) {
return $this->get('account_id');
} else {
return '';
}
}
//...
/src/Appbundle/Controller/DriverController.php
namespace AppBundle\Controller;
use AppBundle\Form\DriverFormType;
use AppBundle\Model\Driversdb\PublicSchema\Driver;
use AppBundle\Model\Driversdb\PublicSchema\DriverModel;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Form\Exception\InvalidArgumentException;
use Symfony\Component\HttpFoundation\Request;
use AppBundle\Service\DriverToJson;
class DriverController extends Controller
{
//...
/**
* @Route("/driver", name="driver_create")
* @Method ("POST")
* @Template("@App/Driver/new.html.twig")
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* @throws \Exception
*/
public function createAction(Request $request){
$driver = new Driver();
$form = $this->createForm(DriverFormType::class, $driver,[
'action'=> $this->generateUrl('driver_create'),
'method'=> 'POST'
]);
$form->handleRequest($request);
if($form->isValid()){
$driver = $form->getData();
try{
/** @var DriverModel $driverModel */
$driverModel = $this->get('pomm')['driversdb']->getModel(DriverModel::class);
$driverModel->insertOne($driver);
return $this->redirectToRoute('driver_list');
}catch (\Exception $e){
throw $e;
}
}
throw new InvalidArgumentException('Invalid form data');
}
//...
}
/src/AppBundle/Form/DriverFormType.php
namespace AppBundle\Form;
use AppBundle\Model\Driversdb\PublicSchema\Driver;
use AppBundle\Service\DriverToJson;
use PommProject\Foundation\Converter\ConverterPooler;
use PommProject\PommBundle\Request\ParamConverter\EntityParamConverter;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DriverFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options){
$builder
->add('testinfo', 'extrainfo', array('mapped'=>false))
->add('account_id', TextType::class)
->add('ssn', TextType::class,array(
'attr' => [
'class' => 'col-xs-12'
]
))
// ... many other fields.
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class'=> Driver::class,
'attr'=>array('novalidate'=>'novalidate'),
]);
}
}
Конвертер Pomm использует тип поля, чтобы определить, к какому конвертеру следует обращаться. Ваше поле должно быть extrainfo
,
Создайте этот новый тип:
CREATE DOMAIN extrainfo AS jsonb;
И использовать его для infodata
колонка:
ALTER TABLE driver ALTER COLUMN infodata TYPE extrainfo;
Других решений пока нет …