В случае, если наш бандл имеет некоторые сущности, которые могут быть переопределены в проекте, в который бандл будет установлен, может возникнуть вопрос наследования от этих сущностей.
Например, мой бандл параметров товаров для интернет-магазина определяет сущности Product и Category, где определяются зависимости от сущностей бандла. И эти сущности Product и Category скорее всего должны быть дополнены специфическими полями в проекте.
Можно в такой ситуации сделать так:
namespace Onest\EshopParamsBundle\Entity;
// Родительский класс
/**
* @ORM\MappedSuperclass
*/
class Product
{
/**
* @ORM\OneToMany(targetEntity="Onest\EshopParamsBundle\Entity\Parameter", mappedBy="product", cascade={"persist", "remove"})
*/
protected $parameters;
...
// логика, которую нужно будет унаследовать
...
}
namespace App\Entity;
// Дочерний класс
/**
* @ORM\Entity
*/
class Product extends \Onest\EshopParamsBundle\Entity\Product
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
...
}
Ссылка в тему:
https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/inheritance-mapping.html
Структура бандла почти повторяет структуру обычного проекта на Symfony.
Допустим, есть entity Product, к которому привязаны ProductCharacteristic. В Sonata Admin последние вводятся / вводятся при помощи Sonata\Form\Type\CollectionType. Выглядит это примерно так:
А в коде так:
$formMapper
->add('characteristics', CollectionType::class, [
'label' => 'Характеристики',
'required' => false,
'type_options' => [
'delete' => true,
],
], [
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position',
])
;
Обратите внимание на ‘sortable’ => ‘position’. Это поле, в которое записывается порядок вывода.
И «из коробки» эта конструкция ПОЧТИ работает. То есть мышью все таскается, но при сохранении возвращается на исходную позицию.
class ProductCharacteristic
{
...
/**
* @ORM\Column(type="integer")
*/
private $position = 0;
...
}
class Product
{
...
/**
* @ORM\OneToMany(targetEntity="App\Entity\ProductCharacteristic", mappedBy="product", cascade={"persist", "remove"})
* @ORM\OrderBy({"position" = "ASC"})
*/
private $characteristics;
...
}
final class ProductCharacteristicAdmin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
...
->add('position', HiddenType::class, [
'label' => 'Порядок',
])
...
}
}
Чтобы не показывать страницу в сайдбаре админки, нужно добавить в конфиг сервисов параметр show_in_dashboard: false.
# config/services.yaml
admin.phones
class App\Admin\PhoneWithMobileOperatorAdmin
arguments ~ App\Entity\PhoneWithMobileOperator ~
tags
name sonata.admin manager_type orm label Телефоны group CMS show_in_dashboard false
Прописываем новый класс в параметрах:
<?php
// config/services.yaml
parameters:
sonata.media.admin.media.class: App\Sonata\MediaBundle\Admin\MediaAdmin
Создаем этот класс, наследуясь от Sonata\MediaBundle\Admin\PHPCR\MediaAdmin:
<?php
// src/Sonata/MediaBundle/Admin/MediaAdmin.php
namespace App\Sonata\MediaBundle\Admin;
use Sonata\MediaBundle\Admin\PHPCR\MediaAdmin as BaseMediaAdmin;
class MediaAdmin extends BaseMediaAdmin
{
protected $datagridValues = array(
'_page' => 1,
'_per_page' => 25,
'_sort_order' => 'DESC',
'_sort_by' => 'createdAt',
);
}