Symfony 如何在Sonata Admin的嵌入式管理类中获取子对象?

Symfony 如何在Sonata Admin的嵌入式管理类中获取子对象?,symfony,sonata-admin,Symfony,Sonata Admin,我试图获取并操作与SonataAdmin中的ImageAdmin类相关的实际对象(使用Symfony 2.3)。当ImageAdmin类是唯一被使用的类时,这可以很好地工作。但是,当ImageAdmin嵌入到另一个管理中时,它会出现可怕的错误 以下是当您没有嵌入式管理员时的工作原理: class ImageAdmin extends Admin { protected $baseRoutePattern = 'image'; protected function configu

我试图获取并操作与SonataAdmin中的ImageAdmin类相关的实际对象(使用Symfony 2.3)。当ImageAdmin类是唯一被使用的类时,这可以很好地工作。但是,当ImageAdmin嵌入到另一个管理中时,它会出现可怕的错误

以下是当您没有嵌入式管理员时的工作原理:

class ImageAdmin extends Admin {
    protected $baseRoutePattern = 'image';

    protected function configureFormFields(FormMapper $formMapper) {
        $subject = $this->getSubject();
    }
}
但当您使用以下命令将ImageAdmin嵌入ParentAdmin时:

class PageAdmin extends Admin {
    protected function configureFormFields(FormMapper $formMapper) {
        $formMapper->add('image1', 'sonata_type_admin');
    }
}
然后,当您编辑id为10的父项并在ImageAdmin中调用getSubject()时,您将得到id为10的图像

换句话说,getSubject()从URL提取id,然后调用
$this->getModelManager()->find($this->getClass(),$id),它交叉引用父id和图像id。哎呀


所以。。。我想做的是能够掌握当前ImageAdmin实例中正在渲染/编辑的实际对象,无论是直接编辑还是通过嵌入表单编辑,然后能够使用它进行操作

也许getSubject()是错误的树,但是我注意到当从ImageAdmin::configureFormFields()调用时,
$this->getCurrentChild()
返回false,即使ImageAdmin是使用sonata\u type\u admin字段类型嵌入的。我很困惑


无论如何,我希望有可能以某种我忽略的明显方式抓住这个物体,这里有人可以帮助启发我

你能试试
$this->getForm()->getViewData()吗在ImageAdmin中?这将为您找到正确的子实体。

多亏Tautrimas提供了一些想法,但我设法找到了答案:

在ImageAdmin中设置:

protected function configureFormFields(FormMapper $formMapper)
{
    if($this->hasParentFieldDescription()) { // this Admin is embedded
        $getter = 'get' . $this->getParentFieldDescription()->getFieldName();
        $parent = $this->getParentFieldDescription()->getAdmin()->getSubject();
        if ($parent) {
          $image = $parent->$getter();
        } else {
          $image = null;
        }
    } else { // this Admin is not embedded
        $image = $this->getSubject();
    }

    // You can then do things with the $image, like show a thumbnail in the help:
    $fileFieldOptions = array('required' => false);
    if ($image && ($webPath = $image->getWebPath())) {
        $fileFieldOptions['help'] = '<img src="'.$webPath.'" class="admin-preview" />';
    }

    $formMapper
        ->add('file', 'file', $fileFieldOptions)
    ;
}
受保护的函数配置FormFields(FormMapper$FormMapper)
{
如果($this->hasParentFieldDescription()){//嵌入了此管理员
$getter='get'.$this->getParentFieldDescription()->getFieldName();
$parent=$this->getParentFieldDescription()->getAdmin()->getSubject();
如果($parent){
$image=$parent->$getter();
}否则{
$image=null;
}
}否则{//此管理员未嵌入
$image=$this->getSubject();
}
//然后,您可以使用$image执行一些操作,例如在帮助中显示缩略图:
$fileFieldOptions=array('required'=>false);
如果($image&($webPath=$image->getWebPath()){
$fileFieldOptions['help']='';
}
$formMapper
->添加('file','file',$fileFieldOptions)
;
}
我会在即将出版的SonataAdmin食谱中发布这一点


卡波尼卡的解决方案只适用于一对一的关系,对吗?在我的oneToMany示例中,这个:$parent->$getter()返回一个集合,我不知道如何识别当前主题。 我发现了这个bug报告: ,其中包含对此的修复,但它仍处于打开状态,因此我希望他们很快将其合并:(

编辑

通过一些研究,可以暂时解决这个问题:

简言之:

创建类并复制粘贴此文件的内容: 然后将其添加到services.yml,并将类名称空间更改为新的类名称空间:

services:
sonata.admin.form.type.admin:
    class: ACME\AdminBundle\Form\Type\AdminType
    tags:
        - { name: form.type, alias: sonata_type_admin }
但它仍然有一个bug:

此外,如果在父文档中启用了cascade_验证,并且嵌入表单有错误,则修复程序也不起作用


我尝试了所有这些解决方案,但没有一个成功。
所以,我努力寻找解决方案。我的解决方案基于caponica的解决方案,但只针对一个案例。我找到的解决方案是一种变通方法,但效果很好。
它正在使用会话工作。

public function getCurrentObjectFromCollection($adminChild)
    {
    $getter = 'get' . $adminChild->getParentFieldDescription()
                               ->getFieldName();
    $parent = $adminChild->getParentFieldDescription()
                   ->getAdmin()
                   ->getSubject();
    $collection = $parent->$getter();

    $session = $adminChild->getRequest()->getSession();
    $number = 0;
    if ($session->get('adminCollection')) {
        $number = $session->get('adminCollection');
        $session->remove('adminCollection');
    }
    else {
        $session->set('adminCollection', 1 - $number);
    }

    return $collection[$number];
}
您可以通过以下方式在管理中获得正确的对象:

    $object = $this->getCurrentObjectFromCollection($this)
因此,当父级需要显示子管理员列表时,每个子管理员都将运行此功能并更新会话参数。当所有元素都已获取时,会话参数将被删除。
此代码适用于只有2个元素的列表,但可以针对任意数量的元素进行更新。


希望这对某人有所帮助:)

我也遇到了同样的问题,我可以通过“自定义表单类型扩展”来实现这一点,其中的文档在链接“”中给出


这是一个完美的解决方案。

$this->getForm()->getViewData()
放入
ImageAdmin::configureFormFields()
似乎会导致无限循环、内存不足错误和白屏死亡。。。哎呀!那么可能
$formMapper->getFormBuilder()->getForm()->getViewData()
会有帮助吗?好吧,这可以防止爆炸,但是
getViewData()
即使我正在编辑的页面上有一个相关的图像,也会返回NULL。您可以做的另一件事是。通过这种方式,您可以执行
$formMapper->getFormBuilder()->addEventListener(FormEvents::POST_SUBMIT,函数(FormEvent$event){$subject=$event->getForm()->getViewData();})。只需使用您需要的适当事件类型。问题是,我没有找到一个简单的方法来修改奏鸣曲的形式。谢谢你的想法!然而,我不认为POST_提交会有帮助。。。我试图在用户提交表单之前在表单上显示一些内容!不过,我会仔细研究一下,也许预先设置的数据会有所帮助。卡波尼卡的解决方案只适用于一对一的关系,对吗?在我的oneToMany示例中,这个:$parent->$getter()返回一个集合,我不知道如何识别当前主题。我发现了此错误报告:,其中包含对此的修复,但它仍然处于打开状态,因此我希望他们很快将其合并:(