Ответ 1
У меня была такая же проблема, как у вас, но я понял это.
Прежде всего, вы можете выбрать для отношения "один-ко-многим/много-к-одному" (используя промежуточный объект) вместо отношения "многие ко многим". Зачем? Потому что это позволяет использовать дополнительные столбцы, такие как столбец position
. Таким образом вы можете изменить порядок изображений по своему желанию. В отношении "многие ко многим" таблица ссылок имеет только два столбца: идентификатор связанных таблиц.
(...) часто вы хотите связать дополнительные атрибуты с ассоциацией, и в этом случае вы вводите класс ассоциации. Следовательно, прямая ассоциация "многие-ко-многим" исчезает и заменяется ассоциациями "один-много-много-много-один" между 3 участвующими классами.
Итак, я добавил это в файл сопоставления продукта: (как вы можете видеть, я использую YAML в качестве формата файла конфигурации)
oneToMany:
images:
targetEntity: MyBundle\Entity\ProductImage
mappedBy: product
orderBy:
position: ASC
И я создал новый файл сопоставления ProductImage:
MyBundle\Entity\ProductImage:
type: entity
table: product_images
id:
id:
type: integer
generator: { strategy: AUTO }
fields:
position:
type: integer
manyToOne:
product:
targetEntity: MyBundle\Entity\Product
inversedBy: images
image:
targetEntity: Application\Sonata\MediaBundle\Entity\Media
Используя командную строку (php app/console doctrine:generate:entities MyBundle
), я создал/обновил соответствующие объекты (Product
и ProductImage
).
Далее я создал/обновил классы Admin. ProductAdmin.php:
class ProductAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
// define other form fields
->add('images', 'sonata_type_collection', array(
'required' => false
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position',
))
;
}
ProductImageAdmin.php:
class ProductImageAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('image', 'sonata_type_model_list', array(
'required' => false
), array(
'link_parameters' => array(
'context' => 'product_image'
)
))
->add('position', 'hidden')
;
}
Не забудьте добавить оба из них в качестве сервисов. Если вы не хотите, чтобы ссылка на форму ProductImage отображалась на панели управления, добавьте тег show_in_dashboard: false
. (как вы это делаете, зависит от используемого вами формата конфигурации (yaml/xml/php))
После этого у меня была правильная форма администратора, однако у меня все еще были проблемы с попыткой сохранить продукты. Я должен был выполнить следующие шаги, чтобы исправить все проблемы:
Во-первых, мне пришлось настраивать операции кэширования для объекта Product. Опять же, как это сделать, зависит от вашего формата конфигурации. Я использую yaml, поэтому в отношениях images
one-to-many я добавил свойство cascade:
oneToMany:
images:
targetEntity: MyBundle\Entity\ProductImage
mappedBy: product
orderBy:
position: ASC
cascade: ["persist"]
Это заставило его работать (или так я думал), но я заметил, что product_id
в базе данных был установлен в NULL
. Я решил это, добавив методы prePersist()
и preUpdate()
в класс ProductAdmin
:
public function prePersist($object)
{
foreach ($object->getImages() as $image) {
$image->setProduct($object);
}
}
public function preUpdate($object)
{
foreach ($object->getImages() as $image) {
$image->setProduct($object);
}
}
... и добавил одну строку к методу addImages()
объекта Product
:
public function addImage(\MyBundle\Entity\ProductImage $images)
{
$images->setProduct($this);
$this->images[] = $images;
return $this;
}
Это сработало для меня, теперь я могу добавлять, изменять, изменять порядок, удалять и т.д. изображения в/из моих продуктов.