Symfony3.3+Sonata:如何为sonata_type_model启用自定义排序?
解决Sonata Admin中多对多关联的自定义排序问题
嘿,我之前在Sonata Admin里处理多对多关联的自定义排序时也踩过一模一样的坑!原生的多对多关联因为没有存储排序信息的字段,根本没法支持用户自定义调整顺序,更别说删除中间项后排序混乱的问题了。咱们可以通过把多对多拆成一对多+多对一的中间实体结构来解决,具体步骤如下:
1. 创建中间实体存储排序字段
首先需要新建一个中间实体(比如QuestionGalleryItem),用来关联Question和QuestionGallery,同时添加position字段保存排序位置:
// src/AppBundle/Entity/QuestionGalleryItem.php namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table(name="question_gallery_item") */ class QuestionGalleryItem { /** * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") * @ORM\Column(type="integer") */ private $id; /** * @ORM\ManyToOne(targetEntity="QuestionGallery", inversedBy="galleryItems") * @ORM\JoinColumn(nullable=false) */ private $gallery; /** * @ORM\ManyToOne(targetEntity="Question", inversedBy="galleryItems") * @ORM\JoinColumn(nullable=false) */ private $question; /** * @ORM\Column(type="integer") */ private $position = 0; // 生成对应的getter和setter方法 public function getId() { return $this->id; } public function setGallery(QuestionGallery $gallery) { $this->gallery = $gallery; return $this; } public function getGallery() { return $this->gallery; } public function setQuestion(Question $question) { $this->question = $question; return $this; } public function getQuestion() { return $this->question; } public function setPosition(int $position) { $this->position = $position; return $this; } public function getPosition() { return $this->position; } }
2. 修改原有实体的关联关系
把QuestionGallery和Question的多对多关联改成一对多关联到中间实体:
修改QuestionGallery实体
// src/AppBundle/Entity/QuestionGallery.php namespace AppBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class QuestionGallery { // ... 原有字段和方法 /** * @ORM\OneToMany(targetEntity="QuestionGalleryItem", mappedBy="gallery", cascade={"persist", "remove"}, orphanRemoval=true) * @ORM\OrderBy({"position" = "ASC"}) */ private $galleryItems; public function __construct() { $this->galleryItems = new ArrayCollection(); } public function addGalleryItem(QuestionGalleryItem $item) { $item->setGallery($this); if (!$this->galleryItems->contains($item)) { $this->galleryItems->add($item); } return $this; } public function removeGalleryItem(QuestionGalleryItem $item) { $this->galleryItems->removeElement($item); return $this; } public function getGalleryItems() { return $this->galleryItems; } }
修改Question实体(类似操作)
// src/AppBundle/Entity/Question.php namespace AppBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class Question { // ... 原有字段和方法 /** * @ORM\OneToMany(targetEntity="QuestionGalleryItem", mappedBy="question", cascade={"persist", "remove"}) */ private $galleryItems; public function __construct() { $this->galleryItems = new ArrayCollection(); } // 对应的add/remove/getGalleryItems方法 }
3. 配置Sonata Admin的表单字段
在QuestionGalleryAdmin里,用sonata_type_collection替代原来的sonata_type_model,并开启排序支持:
// src/AppBundle/Admin/QuestionGalleryAdmin.php namespace AppBundle\Admin; use Sonata\AdminBundle\Admin\AbstractAdmin; use Sonata\AdminBundle\Form\FormMapper; use Sonata\AdminBundle\Form\Type\CollectionType; class QuestionGalleryAdmin extends AbstractAdmin { protected function configureFormFields(FormMapper $formMapper) { $formMapper // ... 其他表单字段 ->add('galleryItems', CollectionType::class, [ 'label' => 'Gallery Questions', 'by_reference' => false, 'allow_add' => true, 'allow_delete' => true, 'sortable' => true, 'sortable_field' => 'position', 'required' => false, ], [ 'edit' => 'inline', 'inline' => 'table', // 用表格形式展示,方便拖拽排序 'sortable' => 'position', ]) ; } // 自动重新排序position字段,解决删除中间项后的排序混乱 public function preUpdate($object) { $this->reorderPositions($object->getGalleryItems()); parent::preUpdate($object); } public function prePersist($object) { $this->reorderPositions($object->getGalleryItems()); parent::prePersist($object); } private function reorderPositions($items) { $position = 0; foreach ($items as $item) { $item->setPosition($position++); } } }
4. 最后一步:更新数据库
执行Doctrine的迁移命令来创建中间表:
php bin/console doctrine:schema:update --force
这样设置后,用户就能在Sonata Admin的表单里拖拽调整Question的顺序,删除中间项后,剩余项的position也会自动重新排序,完全解决你遇到的问题!
内容的提问来源于stack exchange,提问作者Mayor of the Plattenbaus
相关产品推荐
相关产品推荐

