Sonata Admin (2.3) 中的嵌套集合字段
Nested collection fields in Sonata Admin (2.3)
我在创建用于创建课程的表单时遇到问题。这是我的数据库方案的一部分,我正在尝试为其创建一个表单:
所以我想做的是创建一个课程,我可以在其中创建会话和附加到该会话的日期(时刻)。它应该看起来像这样:
在我的 CourseAdmin class 我有:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name', 'text', array('label' => 'Naam'))
->add('description', 'textarea', array('label' => 'Beschrijving'))
->add('materials', 'textarea', array('label' => 'Benodigde materialen'))
->add('numberOfParticipants', 'number', array('label' => 'Aantal deelnembers'))
->add('numberOfDays', 'number', array('label' => 'Aantal dagen'))
->add('price', 'number', array('label' => 'Prijs'))
->add('priceKmo', 'number', array('label' => 'KMO-portefeuille Prijs'))
->add('location', 'sonata_type_model', array('expanded' => true, 'by_reference' => false, 'multiple' => true, 'btn_add' => false))
->add('session', 'sonata_type_collection', array(
'by_reference' => false,
'type_options' => array(
// Prevents the "Delete" option from being displayed
'delete' => false,
'delete_options' => array(
// You may otherwise choose to put the field but hide it
'type' => 'hidden',
// In that case, you need to fill in the options as well
'type_options' => array(
'mapped' => false,
'required' => false,
)
)
)
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position'
))
;
}
在我的 SessionAdmin class 我有:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('type', 'text', array('label' => 'Type opleiding (Dag / Avond)'))
->add('moment', 'sonata_type_collection', array(
'by_reference' => false,
'type_options' => array(
// Prevents the "Delete" option from being displayed
'delete' => false,
'delete_options' => array(
// You may otherwise choose to put the field but hide it
'type' => 'hidden',
// In that case, you need to fill in the options as well
'type_options' => array(
'mapped' => false,
'required' => false,
)
)
)
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position'
))
;
}
在我的 MomentAdmin class 我有:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('time', 'date', array('label' => 'Datum'))
;
}
我的表单中的问题是当我尝试向我的会话添加时刻(日期)时出现以下错误:
FatalErrorException: Error: Call to a member function getName() on null in /myproject/app/cache/dev/classes.php line 9772
所以,我可以添加一个会话,但是当我尝试向我的会话添加一个时刻时,我收到了错误...。
当我在文件 classes.php 中查看规则 9771 和 9772 时,有:
$childFormBuilder = $this->getChildFormBuilder($formBuilder, $elementId);
$fieldDescription = $admin->getFormFieldDescription($childFormBuilder->getName());
$childFormBuilder
为null。
当我查看那个函数时,我得到了这个:
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
if ($name == $elementId) {
return $formBuilder;
}
}
return;
}
当我像这样对 $name 和 $elementId 执行 var_dump 时:
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
var_dump("name: " . $name);
var_dump("elementId: " . $elementId);
if ($name == $elementId) {
return $formBuilder;
}
}
die;
return;
}
然后按下添加新按钮,如下图所示:
然后我得到这个输出:
name: s56cda71d2daa0_name
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_description
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_materials
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_numberOfParticipants
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_numberOfDays
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_price
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_priceKmo
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_location
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_session
elementId: s56cda71d2daa0_session_0_moment
在我所有的实体中,我都有一个 __toString 函数。我的课程实体中的示例:
public function __toString()
{
if(!is_null($this->name))
{
return $this->name;
}
else{
return "";
}
}
这可能是什么问题?我真的坚持这个。我还在 Sonata Admin 的 github 回购上发布了一个 issue 但没有答案......
我的实体:
课程实体:
<?php
namespace Studyx\EnrolmentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Course
*
* @ORM\Table(name="course")
* @ORM\Entity
*/
class Course
{
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255, nullable=false)
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="description", type="text", nullable=false)
*/
private $description;
/**
* @var string
*
* @ORM\Column(name="materials", type="text", nullable=true)
*/
private $materials;
/**
* @var integer
*
* @ORM\Column(name="number_of_participants", type="integer", nullable=true)
*/
private $numberOfParticipants;
/**
* @var integer
*
* @ORM\Column(name="number_of_days", type="integer", nullable=true)
*/
private $numberOfDays;
/**
* @var string
*
* @ORM\Column(name="price", type="decimal", nullable=true)
*/
private $price;
/**
* @var string
*
* @ORM\Column(name="price_kmo", type="decimal", nullable=true)
*/
private $priceKmo;
/**
* @var integer
*
* @ORM\Column(name="ID", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="Studyx\EnrolmentBundle\Entity\Location", inversedBy="course")
* @ORM\JoinTable(name="course_has_location",
* joinColumns={
* @ORM\JoinColumn(name="course_ID", referencedColumnName="ID")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="location_ID", referencedColumnName="ID")
* }
* )
*/
private $location;
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\OneToMany(targetEntity="Studyx\EnrolmentBundle\Entity\Session", mappedBy="course")
*/
private $session;
/**
* Add session
*
* @param \Studyx\EnrolmentBundle\Entity\Session $session
* @return Session
*/
public function addSession(\Studyx\EnrolmentBundle\Entity\Session $session)
{
$this->session[] = $session;
return $this;
}
/**
* Remove session
*
* @param \Studyx\EnrolmentBundle\Entity\Session $session
*/
public function removeSession(\Studyx\EnrolmentBundle\Entity\Session $session)
{
$this->session->removeElement($session);
}
/**
* Get session
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getSession()
{
return $this->session;
}
/**
* Constructor
*/
public function __construct()
{
$this->location = new \Doctrine\Common\Collections\ArrayCollection();
}
public function __toString()
{
if(!is_null($this->name))
{
return $this->name;
}
else{
return "";
}
}
/**
* Set name
*
* @param string $name
* @return Course
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set description
*
* @param string $description
* @return Course
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set materials
*
* @param string $materials
* @return Course
*/
public function setMaterials($materials)
{
$this->materials = $materials;
return $this;
}
/**
* Get materials
*
* @return string
*/
public function getMaterials()
{
return $this->materials;
}
/**
* Set numberOfParticipants
*
* @param integer $numberOfParticipants
* @return Course
*/
public function setNumberOfParticipants($numberOfParticipants)
{
$this->numberOfParticipants = $numberOfParticipants;
return $this;
}
/**
* Get numberOfParticipants
*
* @return integer
*/
public function getNumberOfParticipants()
{
return $this->numberOfParticipants;
}
/**
* Set numberOfDays
*
* @param integer $numberOfDays
* @return Course
*/
public function setNumberOfDays($numberOfDays)
{
$this->numberOfDays = $numberOfDays;
return $this;
}
/**
* Get numberOfDays
*
* @return integer
*/
public function getNumberOfDays()
{
return $this->numberOfDays;
}
/**
* Set price
*
* @param string $price
* @return Course
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* @return string
*/
public function getPrice()
{
return $this->price;
}
/**
* Set priceKmo
*
* @param string $priceKmo
* @return Course
*/
public function setPriceKmo($priceKmo)
{
$this->priceKmo = $priceKmo;
return $this;
}
/**
* Get priceKmo
*
* @return string
*/
public function getPriceKmo()
{
return $this->priceKmo;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add location
*
* @param \Studyx\EnrolmentBundle\Entity\Location $location
* @return Course
*/
public function addLocation(\Studyx\EnrolmentBundle\Entity\Location $location)
{
$this->location[] = $location;
return $this;
}
/**
* Remove location
*
* @param \Studyx\EnrolmentBundle\Entity\Location $location
*/
public function removeLocation(\Studyx\EnrolmentBundle\Entity\Location $location)
{
$this->location->removeElement($location);
}
/**
* Get location
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getLocation()
{
return $this->location;
}
}
会话实体:
<?php
namespace Studyx\EnrolmentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Session
*
* @ORM\Table(name="session")
* @ORM\Entity
*/
class Session
{
/**
* @var string
*
* @ORM\Column(name="type", type="string", length=45, nullable=false)
*/
private $type;
/**
* @var integer
*
* @ORM\Column(name="ID", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var \Studyx\EnrolmentBundle\Entity\Course
*
* @ORM\ManyToOne(targetEntity="Studyx\EnrolmentBundle\Entity\Course", inversedBy="session")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="course_ID", referencedColumnName="ID")
* })
*/
private $course;
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\OneToMany(targetEntity="Studyx\EnrolmentBundle\Entity\Moment", mappedBy="session")
*/
private $moment;
/**
* Add moment
*
* @param \Studyx\EnrolmentBundle\Entity\Moment $moment
* @return Moment
*/
public function addMoment(\Studyx\EnrolmentBundle\Entity\Moment $moment)
{
$this->moment[] = $moment;
return $this;
}
/**
* Remove moment
*
* @param \Studyx\EnrolmentBundle\Entity\Moment $moment
*/
public function removeMoment(\Studyx\EnrolmentBundle\Entity\Moment $moment)
{
$this->moment->removeElement($moment);
}
/**
* Get moment
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getMoment()
{
return $this->moment;
}
public function __toString()
{
if(!is_null($this->type))
{
return $this->type;
}
else{
return "";
}
}
/**
* Set type
*
* @param string $type
* @return Session
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get type
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set course
*
* @param \Studyx\EnrolmentBundle\Entity\Course $course
* @return Session
*/
public function setCourse(\Studyx\EnrolmentBundle\Entity\Course $course = null)
{
$this->course = $course;
return $this;
}
/**
* Get course
*
* @return \Studyx\EnrolmentBundle\Entity\Course
*/
public function getCourse()
{
return $this->course;
}
}
时刻实体:
<?php
namespace Studyx\EnrolmentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Moment
*
* @ORM\Table(name="moment")
* @ORM\Entity
*/
class Moment
{
/**
* @var \DateTime
*
* @ORM\Column(name="time", type="datetime", nullable=false)
*/
private $time;
/**
* @var integer
*
* @ORM\Column(name="ID", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var \Studyx\EnrolmentBundle\Entity\Session
*
* @ORM\ManyToOne(targetEntity="Studyx\EnrolmentBundle\Entity\Session")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="session_ID", referencedColumnName="ID")
* })
*/
private $session;
public function __toString()
{
if(!is_null($this->time))
{
return $this->time;
}
else{
return "";
}
}
/**
* Set time
*
* @param \DateTime $time
* @return Moment
*/
public function setTime($time)
{
$this->time = $time;
return $this;
}
/**
* Get time
*
* @return \DateTime
*/
public function getTime()
{
return $this->time;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set session
*
* @param \Studyx\EnrolmentBundle\Entity\Session $session
* @return Moment
*/
public function setSession(\Studyx\EnrolmentBundle\Entity\Session $session = null)
{
$this->session = $session;
return $this;
}
/**
* Get session
*
* @return \Studyx\EnrolmentBundle\Entity\Session
*/
public function getSession()
{
return $this->session;
}
}
更新:
我在函数 getChildFormBuilder 中添加了一些 var_dump,如下所示:
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
if ($name == $elementId) {
return $formBuilder;
}
}
var_dump(__METHOD__);
var_dump($elementId);
var_dump(debug_backtrace());
return;
}
结果是这样的:
string 'Sonata\AdminBundle\Admin\AdminHelper::getChildFormBuilder' (length=57)
string 's56cdfa72c4dea_session_0_moment' (length=31)
array (size=8)
0 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/cache/dev/classes.php' (length=69)
'line' => int 9774
'function' => string 'getChildFormBuilder' (length=19)
'class' => string 'Sonata\AdminBundle\Admin\AdminHelper' (length=36)
'object' =>
object(Sonata\AdminBundle\Admin\AdminHelper)[339]
protected 'pool' =>
object(Sonata\AdminBundle\Admin\Pool)[104]
...
'type' => string '->' (length=2)
'args' =>
array (size=2)
0 =>
object(Symfony\Component\Form\FormBuilder)[436]
...
1 => &string 's56cdfa72c4dea_session_0_moment' (length=31)
1 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/vendor/sonata-project/admin-bundle/Controller/HelperController.php' (length=110)
'line' => int 95
'function' => string 'appendFormFieldElement' (length=22)
'class' => string 'Sonata\AdminBundle\Admin\AdminHelper' (length=36)
'object' =>
object(Sonata\AdminBundle\Admin\AdminHelper)[339]
protected 'pool' =>
object(Sonata\AdminBundle\Admin\Pool)[104]
...
'type' => string '->' (length=2)
'args' =>
array (size=3)
0 =>
object(Studyx\EnrolmentBundle\Admin\CourseAdmin)[370]
...
1 =>
object(Studyx\EnrolmentBundle\Entity\Course)[415]
...
2 => &string 's56cdfa72c4dea_session_0_moment' (length=31)
2 =>
array (size=5)
'function' => string 'appendFormFieldElementAction' (length=28)
'class' => string 'Sonata\AdminBundle\Controller\HelperController' (length=46)
'object' =>
object(Sonata\AdminBundle\Controller\HelperController)[244]
protected 'twig' =>
object(Twig_Environment)[220]
...
protected 'helper' =>
object(Sonata\AdminBundle\Admin\AdminHelper)[339]
...
protected 'pool' =>
object(Sonata\AdminBundle\Admin\Pool)[104]
...
protected 'validator' =>
object(Symfony\Component\Validator\Validator)[340]
...
'type' => string '->' (length=2)
'args' =>
array (size=1)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
3 =>
array (size=4)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/bootstrap.php.cache' (length=67)
'line' => int 2957
'function' => string 'call_user_func_array' (length=20)
'args' =>
array (size=2)
0 => &
array (size=2)
...
1 => &
array (size=1)
...
4 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/bootstrap.php.cache' (length=67)
'line' => int 2931
'function' => string 'handleRaw' (length=9)
'class' => string 'Symfony\Component\HttpKernel\HttpKernel' (length=39)
'object' =>
object(Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel)[300]
protected 'container' =>
object(appDevDebugProjectContainer)[304]
...
protected 'dispatcher' =>
object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher)[299]
...
protected 'resolver' =>
object(Symfony\Component\HttpKernel\Controller\TraceableControllerResolver)[249]
...
'type' => string '->' (length=2)
'args' =>
array (size=2)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
1 => &int 1
5 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/bootstrap.php.cache' (length=67)
'line' => int 3060
'function' => string 'handle' (length=6)
'class' => string 'Symfony\Component\HttpKernel\HttpKernel' (length=39)
'object' =>
object(Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel)[300]
protected 'container' =>
object(appDevDebugProjectContainer)[304]
...
protected 'dispatcher' =>
object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher)[299]
...
protected 'resolver' =>
object(Symfony\Component\HttpKernel\Controller\TraceableControllerResolver)[249]
...
'type' => string '->' (length=2)
'args' =>
array (size=3)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
1 => &int 1
2 => &boolean true
6 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/bootstrap.php.cache' (length=67)
'line' => int 2333
'function' => string 'handle' (length=6)
'class' => string 'Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel' (length=73)
'object' =>
object(Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel)[300]
protected 'container' =>
object(appDevDebugProjectContainer)[304]
...
protected 'dispatcher' =>
object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher)[299]
...
protected 'resolver' =>
object(Symfony\Component\HttpKernel\Controller\TraceableControllerResolver)[249]
...
'type' => string '->' (length=2)
'args' =>
array (size=3)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
1 => &int 1
2 => &boolean true
7 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/web/app_dev.php' (length=59)
'line' => int 29
'function' => string 'handle' (length=6)
'class' => string 'Symfony\Component\HttpKernel\Kernel' (length=35)
'object' =>
object(AppKernel)[5]
protected 'bundles' =>
array (size=22)
...
protected 'bundleMap' =>
array (size=22)
...
protected 'container' =>
object(appDevDebugProjectContainer)[304]
...
protected 'rootDir' => string '/Applications/MAMP/htdocs/studyx_enrolments/app' (length=47)
protected 'environment' => string 'dev' (length=3)
protected 'debug' => boolean true
protected 'booted' => boolean true
protected 'name' => string 'app' (length=3)
protected 'startTime' => float 1456339594.61
protected 'loadClassCache' =>
array (size=2)
...
'type' => string '->' (length=2)
'args' =>
array (size=1)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
更新 2:
我已将 composer.json 中的要求更改为 "sonata-project/admin-bundle": "^2.4@dev" 并使用 composer 进行了更新。但是现在我收到了这个错误:
ContextErrorException: Warning: Illegal string offset 'admin' in
app/cache/dev/classes.php line 10482
错误在这个函数中:
public function getDashboardGroups()
{
$groups = $this->adminGroups;
foreach ($this->adminGroups as $name => $adminGroup) {
if (isset($adminGroup['items'])) {
foreach ($adminGroup['items'] as $key => $item) {
if (''!= $item['admin']) {
$admin = $this->getInstance($item['admin']);
if ($admin->showIn(Admin::CONTEXT_DASHBOARD)) {
$groups[$name]['items'][$key] = $admin;
} else {
unset($groups[$name]['items'][$key]);
}
}
else {
unset($groups[$name]['items'][$key]);
}
}
}
if (empty($groups[$name]['items'])) {
unset($groups[$name]);
}
}
return $groups;
}
在线错误:if (''!= $item['admin']) {
.
在我的 config.yml 我有:
sonata_admin:
title: Studyx
title_logo: bundles/studyxenrolment/images/logo.png
templates:
layout: StudyxEnrolmentBundle:Admin:standard_layout.html.twig
edit: StudyxEnrolmentBundle:CRUD:edit.html.twig
user_block: StudyxEnrolmentBundle:Admin:user_block.html.twig
# search: SonataAdminBundle:Core:search.html.twig
# search_result_block: SonataAdminBundle:Block:block_search_result.html.twig
dashboard:
groups:
studyx.admin.group.inschrijvingen:
label: Inschrijvingen
items: ~
item_adds:
- sonata.admin.enrolment
studyx.admin.group.algemeen:
label: Algemeen
items: ~
item_adds:
- sonata.admin.course
- sonata.admin.student
studyx.admin.group.extra:
label: Extra
items: ~
item_adds:
- sonata.admin.location
blocks:
-
position: top
class: col-md-12
type: sonata.admin.block.admin_list
所以我认为函数 getDashboardGroups 被调用了。
更新 3:
在我的 composer.json 中,我现在有以下内容:
"sonata-project/block-bundle": "~2.3",
"sonata-project/admin-bundle": "^2.4@dev",
"sonata-project/doctrine-orm-admin-bundle": "2.3.*",
"sonata-project/formatter-bundle": "^2.3"
我应该将它们全部更新为 ^2.4@dev
吗?
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
if ($name == $elementId) {
return $formBuilder;
}
}
return;
}
在循环中转储名称和元素 ID 不会完成任何事情。当没有什么可迭代时,您的应用程序显然会崩溃 - 然后它遍历循环,退出并转到返回 NULL
的最后一行。
我建议你在循环之后转储元素 id,如下所示。使用 debug_backtrace 也可能有帮助:
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
if ($name == $elementId) {
return $formBuilder;
}
}
var_dump(__METHOD__);
var_dump($elementId);
var_dump(debug_backtrace());
return;
}
出现此错误是因为您有超过两层的嵌套集合表单,目前任何版本的 sonata-admin 均不支持它。
来自 @rande (owner) and sonata maintainers at issues #262, #1228, #1327 and #1971 :
This is still not supported for now ....
您也可以查看这个旧的 PR #1971,它应该只解决某些用例的问题。
我建议您的解决方案是实施上次打开的 PR #2985 提供的修复程序。
因为 PR 没有合并,所以你需要告诉作曲家加载它而不是当前(不按预期工作)版本。 (参见 composer and VCS)。
希望PR早日合并
在此之前,请随时直接使用它来解决您的问题,就像很多人一样。
更新
最近合并了Pull Request #3553并修复了嵌套集合在> 2 levels (nested in nested)的问题。
要获得固定版本,您必须使用捆绑包的 dev-master
标签(至少来自 commit 926f159 代表 PR 的合并)。
我试过了,它可以很好地满足以下要求:
// composer.json
"require": {
"sonata-project/admin-bundle": "^2.4@dev",
...
},
希望您可以轻松升级捆绑包以获得修复。
更新2
显然,您的作曲家没有接受分支的最后更改。
PR #2739 提供的修复已在 6 天前合并。
要修复最后一个(希望),您需要更改位于 vendor/sonata-project/admin-bundle/DependencyInjection/Compiler/AddDependencyCallsCompilerPass
的 AddDepencyCallsCompilerPass
中的一个非常短的代码块。
在第 95 行,替换此行:
$groupDefaults[$resolvedGroupName]['items'][] = $id;
致那些:
$groupDefaults[$resolvedGroupName]['items'][] = array(
'admin' => $id,
'label' => !empty($attributes['label']) ? $attributes['label'] : '',
'route' => '',
'route_params' => array(),
);
就像 PR 所做的那样(这是使其正常工作所需的唯一更改)。
我会手动进行修复,因为它是非常新的,并且在一些 days/weeks、运行 之后执行以下命令:
composer clear-cache
和 composer update sonata-project/admin-bundle
您应该在手动添加修复之前尝试一下,也许会添加更改。
此外,您可以使用我在回答开头给出的关于 composer 和 VCS 的 link 并直接要求修复。这是您自己的欣赏,因为它是目前的解决方案。
最后,请耐心等待,修复将很快合并到稳定版本中。
我在创建用于创建课程的表单时遇到问题。这是我的数据库方案的一部分,我正在尝试为其创建一个表单:
所以我想做的是创建一个课程,我可以在其中创建会话和附加到该会话的日期(时刻)。它应该看起来像这样:
在我的 CourseAdmin class 我有:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name', 'text', array('label' => 'Naam'))
->add('description', 'textarea', array('label' => 'Beschrijving'))
->add('materials', 'textarea', array('label' => 'Benodigde materialen'))
->add('numberOfParticipants', 'number', array('label' => 'Aantal deelnembers'))
->add('numberOfDays', 'number', array('label' => 'Aantal dagen'))
->add('price', 'number', array('label' => 'Prijs'))
->add('priceKmo', 'number', array('label' => 'KMO-portefeuille Prijs'))
->add('location', 'sonata_type_model', array('expanded' => true, 'by_reference' => false, 'multiple' => true, 'btn_add' => false))
->add('session', 'sonata_type_collection', array(
'by_reference' => false,
'type_options' => array(
// Prevents the "Delete" option from being displayed
'delete' => false,
'delete_options' => array(
// You may otherwise choose to put the field but hide it
'type' => 'hidden',
// In that case, you need to fill in the options as well
'type_options' => array(
'mapped' => false,
'required' => false,
)
)
)
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position'
))
;
}
在我的 SessionAdmin class 我有:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('type', 'text', array('label' => 'Type opleiding (Dag / Avond)'))
->add('moment', 'sonata_type_collection', array(
'by_reference' => false,
'type_options' => array(
// Prevents the "Delete" option from being displayed
'delete' => false,
'delete_options' => array(
// You may otherwise choose to put the field but hide it
'type' => 'hidden',
// In that case, you need to fill in the options as well
'type_options' => array(
'mapped' => false,
'required' => false,
)
)
)
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'position'
))
;
}
在我的 MomentAdmin class 我有:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('time', 'date', array('label' => 'Datum'))
;
}
我的表单中的问题是当我尝试向我的会话添加时刻(日期)时出现以下错误:
FatalErrorException: Error: Call to a member function getName() on null in /myproject/app/cache/dev/classes.php line 9772
所以,我可以添加一个会话,但是当我尝试向我的会话添加一个时刻时,我收到了错误...。
当我在文件 classes.php 中查看规则 9771 和 9772 时,有:
$childFormBuilder = $this->getChildFormBuilder($formBuilder, $elementId);
$fieldDescription = $admin->getFormFieldDescription($childFormBuilder->getName());
$childFormBuilder
为null。
当我查看那个函数时,我得到了这个:
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
if ($name == $elementId) {
return $formBuilder;
}
}
return;
}
当我像这样对 $name 和 $elementId 执行 var_dump 时:
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
var_dump("name: " . $name);
var_dump("elementId: " . $elementId);
if ($name == $elementId) {
return $formBuilder;
}
}
die;
return;
}
然后按下添加新按钮,如下图所示:
然后我得到这个输出:
name: s56cda71d2daa0_name
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_description
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_materials
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_numberOfParticipants
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_numberOfDays
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_price
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_priceKmo
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_location
elementId: s56cda71d2daa0_session_0_moment
name: s56cda71d2daa0_session
elementId: s56cda71d2daa0_session_0_moment
在我所有的实体中,我都有一个 __toString 函数。我的课程实体中的示例:
public function __toString()
{
if(!is_null($this->name))
{
return $this->name;
}
else{
return "";
}
}
这可能是什么问题?我真的坚持这个。我还在 Sonata Admin 的 github 回购上发布了一个 issue 但没有答案......
我的实体:
课程实体:
<?php
namespace Studyx\EnrolmentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Course
*
* @ORM\Table(name="course")
* @ORM\Entity
*/
class Course
{
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255, nullable=false)
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="description", type="text", nullable=false)
*/
private $description;
/**
* @var string
*
* @ORM\Column(name="materials", type="text", nullable=true)
*/
private $materials;
/**
* @var integer
*
* @ORM\Column(name="number_of_participants", type="integer", nullable=true)
*/
private $numberOfParticipants;
/**
* @var integer
*
* @ORM\Column(name="number_of_days", type="integer", nullable=true)
*/
private $numberOfDays;
/**
* @var string
*
* @ORM\Column(name="price", type="decimal", nullable=true)
*/
private $price;
/**
* @var string
*
* @ORM\Column(name="price_kmo", type="decimal", nullable=true)
*/
private $priceKmo;
/**
* @var integer
*
* @ORM\Column(name="ID", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\ManyToMany(targetEntity="Studyx\EnrolmentBundle\Entity\Location", inversedBy="course")
* @ORM\JoinTable(name="course_has_location",
* joinColumns={
* @ORM\JoinColumn(name="course_ID", referencedColumnName="ID")
* },
* inverseJoinColumns={
* @ORM\JoinColumn(name="location_ID", referencedColumnName="ID")
* }
* )
*/
private $location;
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\OneToMany(targetEntity="Studyx\EnrolmentBundle\Entity\Session", mappedBy="course")
*/
private $session;
/**
* Add session
*
* @param \Studyx\EnrolmentBundle\Entity\Session $session
* @return Session
*/
public function addSession(\Studyx\EnrolmentBundle\Entity\Session $session)
{
$this->session[] = $session;
return $this;
}
/**
* Remove session
*
* @param \Studyx\EnrolmentBundle\Entity\Session $session
*/
public function removeSession(\Studyx\EnrolmentBundle\Entity\Session $session)
{
$this->session->removeElement($session);
}
/**
* Get session
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getSession()
{
return $this->session;
}
/**
* Constructor
*/
public function __construct()
{
$this->location = new \Doctrine\Common\Collections\ArrayCollection();
}
public function __toString()
{
if(!is_null($this->name))
{
return $this->name;
}
else{
return "";
}
}
/**
* Set name
*
* @param string $name
* @return Course
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set description
*
* @param string $description
* @return Course
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* @return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set materials
*
* @param string $materials
* @return Course
*/
public function setMaterials($materials)
{
$this->materials = $materials;
return $this;
}
/**
* Get materials
*
* @return string
*/
public function getMaterials()
{
return $this->materials;
}
/**
* Set numberOfParticipants
*
* @param integer $numberOfParticipants
* @return Course
*/
public function setNumberOfParticipants($numberOfParticipants)
{
$this->numberOfParticipants = $numberOfParticipants;
return $this;
}
/**
* Get numberOfParticipants
*
* @return integer
*/
public function getNumberOfParticipants()
{
return $this->numberOfParticipants;
}
/**
* Set numberOfDays
*
* @param integer $numberOfDays
* @return Course
*/
public function setNumberOfDays($numberOfDays)
{
$this->numberOfDays = $numberOfDays;
return $this;
}
/**
* Get numberOfDays
*
* @return integer
*/
public function getNumberOfDays()
{
return $this->numberOfDays;
}
/**
* Set price
*
* @param string $price
* @return Course
*/
public function setPrice($price)
{
$this->price = $price;
return $this;
}
/**
* Get price
*
* @return string
*/
public function getPrice()
{
return $this->price;
}
/**
* Set priceKmo
*
* @param string $priceKmo
* @return Course
*/
public function setPriceKmo($priceKmo)
{
$this->priceKmo = $priceKmo;
return $this;
}
/**
* Get priceKmo
*
* @return string
*/
public function getPriceKmo()
{
return $this->priceKmo;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add location
*
* @param \Studyx\EnrolmentBundle\Entity\Location $location
* @return Course
*/
public function addLocation(\Studyx\EnrolmentBundle\Entity\Location $location)
{
$this->location[] = $location;
return $this;
}
/**
* Remove location
*
* @param \Studyx\EnrolmentBundle\Entity\Location $location
*/
public function removeLocation(\Studyx\EnrolmentBundle\Entity\Location $location)
{
$this->location->removeElement($location);
}
/**
* Get location
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getLocation()
{
return $this->location;
}
}
会话实体:
<?php
namespace Studyx\EnrolmentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Session
*
* @ORM\Table(name="session")
* @ORM\Entity
*/
class Session
{
/**
* @var string
*
* @ORM\Column(name="type", type="string", length=45, nullable=false)
*/
private $type;
/**
* @var integer
*
* @ORM\Column(name="ID", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var \Studyx\EnrolmentBundle\Entity\Course
*
* @ORM\ManyToOne(targetEntity="Studyx\EnrolmentBundle\Entity\Course", inversedBy="session")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="course_ID", referencedColumnName="ID")
* })
*/
private $course;
/**
* @var \Doctrine\Common\Collections\Collection
*
* @ORM\OneToMany(targetEntity="Studyx\EnrolmentBundle\Entity\Moment", mappedBy="session")
*/
private $moment;
/**
* Add moment
*
* @param \Studyx\EnrolmentBundle\Entity\Moment $moment
* @return Moment
*/
public function addMoment(\Studyx\EnrolmentBundle\Entity\Moment $moment)
{
$this->moment[] = $moment;
return $this;
}
/**
* Remove moment
*
* @param \Studyx\EnrolmentBundle\Entity\Moment $moment
*/
public function removeMoment(\Studyx\EnrolmentBundle\Entity\Moment $moment)
{
$this->moment->removeElement($moment);
}
/**
* Get moment
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getMoment()
{
return $this->moment;
}
public function __toString()
{
if(!is_null($this->type))
{
return $this->type;
}
else{
return "";
}
}
/**
* Set type
*
* @param string $type
* @return Session
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get type
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set course
*
* @param \Studyx\EnrolmentBundle\Entity\Course $course
* @return Session
*/
public function setCourse(\Studyx\EnrolmentBundle\Entity\Course $course = null)
{
$this->course = $course;
return $this;
}
/**
* Get course
*
* @return \Studyx\EnrolmentBundle\Entity\Course
*/
public function getCourse()
{
return $this->course;
}
}
时刻实体:
<?php
namespace Studyx\EnrolmentBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Moment
*
* @ORM\Table(name="moment")
* @ORM\Entity
*/
class Moment
{
/**
* @var \DateTime
*
* @ORM\Column(name="time", type="datetime", nullable=false)
*/
private $time;
/**
* @var integer
*
* @ORM\Column(name="ID", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var \Studyx\EnrolmentBundle\Entity\Session
*
* @ORM\ManyToOne(targetEntity="Studyx\EnrolmentBundle\Entity\Session")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="session_ID", referencedColumnName="ID")
* })
*/
private $session;
public function __toString()
{
if(!is_null($this->time))
{
return $this->time;
}
else{
return "";
}
}
/**
* Set time
*
* @param \DateTime $time
* @return Moment
*/
public function setTime($time)
{
$this->time = $time;
return $this;
}
/**
* Get time
*
* @return \DateTime
*/
public function getTime()
{
return $this->time;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set session
*
* @param \Studyx\EnrolmentBundle\Entity\Session $session
* @return Moment
*/
public function setSession(\Studyx\EnrolmentBundle\Entity\Session $session = null)
{
$this->session = $session;
return $this;
}
/**
* Get session
*
* @return \Studyx\EnrolmentBundle\Entity\Session
*/
public function getSession()
{
return $this->session;
}
}
更新:
我在函数 getChildFormBuilder 中添加了一些 var_dump,如下所示:
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
if ($name == $elementId) {
return $formBuilder;
}
}
var_dump(__METHOD__);
var_dump($elementId);
var_dump(debug_backtrace());
return;
}
结果是这样的:
string 'Sonata\AdminBundle\Admin\AdminHelper::getChildFormBuilder' (length=57)
string 's56cdfa72c4dea_session_0_moment' (length=31)
array (size=8)
0 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/cache/dev/classes.php' (length=69)
'line' => int 9774
'function' => string 'getChildFormBuilder' (length=19)
'class' => string 'Sonata\AdminBundle\Admin\AdminHelper' (length=36)
'object' =>
object(Sonata\AdminBundle\Admin\AdminHelper)[339]
protected 'pool' =>
object(Sonata\AdminBundle\Admin\Pool)[104]
...
'type' => string '->' (length=2)
'args' =>
array (size=2)
0 =>
object(Symfony\Component\Form\FormBuilder)[436]
...
1 => &string 's56cdfa72c4dea_session_0_moment' (length=31)
1 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/vendor/sonata-project/admin-bundle/Controller/HelperController.php' (length=110)
'line' => int 95
'function' => string 'appendFormFieldElement' (length=22)
'class' => string 'Sonata\AdminBundle\Admin\AdminHelper' (length=36)
'object' =>
object(Sonata\AdminBundle\Admin\AdminHelper)[339]
protected 'pool' =>
object(Sonata\AdminBundle\Admin\Pool)[104]
...
'type' => string '->' (length=2)
'args' =>
array (size=3)
0 =>
object(Studyx\EnrolmentBundle\Admin\CourseAdmin)[370]
...
1 =>
object(Studyx\EnrolmentBundle\Entity\Course)[415]
...
2 => &string 's56cdfa72c4dea_session_0_moment' (length=31)
2 =>
array (size=5)
'function' => string 'appendFormFieldElementAction' (length=28)
'class' => string 'Sonata\AdminBundle\Controller\HelperController' (length=46)
'object' =>
object(Sonata\AdminBundle\Controller\HelperController)[244]
protected 'twig' =>
object(Twig_Environment)[220]
...
protected 'helper' =>
object(Sonata\AdminBundle\Admin\AdminHelper)[339]
...
protected 'pool' =>
object(Sonata\AdminBundle\Admin\Pool)[104]
...
protected 'validator' =>
object(Symfony\Component\Validator\Validator)[340]
...
'type' => string '->' (length=2)
'args' =>
array (size=1)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
3 =>
array (size=4)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/bootstrap.php.cache' (length=67)
'line' => int 2957
'function' => string 'call_user_func_array' (length=20)
'args' =>
array (size=2)
0 => &
array (size=2)
...
1 => &
array (size=1)
...
4 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/bootstrap.php.cache' (length=67)
'line' => int 2931
'function' => string 'handleRaw' (length=9)
'class' => string 'Symfony\Component\HttpKernel\HttpKernel' (length=39)
'object' =>
object(Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel)[300]
protected 'container' =>
object(appDevDebugProjectContainer)[304]
...
protected 'dispatcher' =>
object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher)[299]
...
protected 'resolver' =>
object(Symfony\Component\HttpKernel\Controller\TraceableControllerResolver)[249]
...
'type' => string '->' (length=2)
'args' =>
array (size=2)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
1 => &int 1
5 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/bootstrap.php.cache' (length=67)
'line' => int 3060
'function' => string 'handle' (length=6)
'class' => string 'Symfony\Component\HttpKernel\HttpKernel' (length=39)
'object' =>
object(Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel)[300]
protected 'container' =>
object(appDevDebugProjectContainer)[304]
...
protected 'dispatcher' =>
object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher)[299]
...
protected 'resolver' =>
object(Symfony\Component\HttpKernel\Controller\TraceableControllerResolver)[249]
...
'type' => string '->' (length=2)
'args' =>
array (size=3)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
1 => &int 1
2 => &boolean true
6 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/app/bootstrap.php.cache' (length=67)
'line' => int 2333
'function' => string 'handle' (length=6)
'class' => string 'Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel' (length=73)
'object' =>
object(Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel)[300]
protected 'container' =>
object(appDevDebugProjectContainer)[304]
...
protected 'dispatcher' =>
object(Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher)[299]
...
protected 'resolver' =>
object(Symfony\Component\HttpKernel\Controller\TraceableControllerResolver)[249]
...
'type' => string '->' (length=2)
'args' =>
array (size=3)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
1 => &int 1
2 => &boolean true
7 =>
array (size=7)
'file' => string '/Applications/MAMP/htdocs/studyx_enrolments/web/app_dev.php' (length=59)
'line' => int 29
'function' => string 'handle' (length=6)
'class' => string 'Symfony\Component\HttpKernel\Kernel' (length=35)
'object' =>
object(AppKernel)[5]
protected 'bundles' =>
array (size=22)
...
protected 'bundleMap' =>
array (size=22)
...
protected 'container' =>
object(appDevDebugProjectContainer)[304]
...
protected 'rootDir' => string '/Applications/MAMP/htdocs/studyx_enrolments/app' (length=47)
protected 'environment' => string 'dev' (length=3)
protected 'debug' => boolean true
protected 'booted' => boolean true
protected 'name' => string 'app' (length=3)
protected 'startTime' => float 1456339594.61
protected 'loadClassCache' =>
array (size=2)
...
'type' => string '->' (length=2)
'args' =>
array (size=1)
0 =>
object(Symfony\Component\HttpFoundation\Request)[6]
...
更新 2:
我已将 composer.json 中的要求更改为 "sonata-project/admin-bundle": "^2.4@dev" 并使用 composer 进行了更新。但是现在我收到了这个错误:
ContextErrorException: Warning: Illegal string offset 'admin' in app/cache/dev/classes.php line 10482
错误在这个函数中:
public function getDashboardGroups()
{
$groups = $this->adminGroups;
foreach ($this->adminGroups as $name => $adminGroup) {
if (isset($adminGroup['items'])) {
foreach ($adminGroup['items'] as $key => $item) {
if (''!= $item['admin']) {
$admin = $this->getInstance($item['admin']);
if ($admin->showIn(Admin::CONTEXT_DASHBOARD)) {
$groups[$name]['items'][$key] = $admin;
} else {
unset($groups[$name]['items'][$key]);
}
}
else {
unset($groups[$name]['items'][$key]);
}
}
}
if (empty($groups[$name]['items'])) {
unset($groups[$name]);
}
}
return $groups;
}
在线错误:if (''!= $item['admin']) {
.
在我的 config.yml 我有:
sonata_admin:
title: Studyx
title_logo: bundles/studyxenrolment/images/logo.png
templates:
layout: StudyxEnrolmentBundle:Admin:standard_layout.html.twig
edit: StudyxEnrolmentBundle:CRUD:edit.html.twig
user_block: StudyxEnrolmentBundle:Admin:user_block.html.twig
# search: SonataAdminBundle:Core:search.html.twig
# search_result_block: SonataAdminBundle:Block:block_search_result.html.twig
dashboard:
groups:
studyx.admin.group.inschrijvingen:
label: Inschrijvingen
items: ~
item_adds:
- sonata.admin.enrolment
studyx.admin.group.algemeen:
label: Algemeen
items: ~
item_adds:
- sonata.admin.course
- sonata.admin.student
studyx.admin.group.extra:
label: Extra
items: ~
item_adds:
- sonata.admin.location
blocks:
-
position: top
class: col-md-12
type: sonata.admin.block.admin_list
所以我认为函数 getDashboardGroups 被调用了。
更新 3:
在我的 composer.json 中,我现在有以下内容:
"sonata-project/block-bundle": "~2.3",
"sonata-project/admin-bundle": "^2.4@dev",
"sonata-project/doctrine-orm-admin-bundle": "2.3.*",
"sonata-project/formatter-bundle": "^2.3"
我应该将它们全部更新为 ^2.4@dev
吗?
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
if ($name == $elementId) {
return $formBuilder;
}
}
return;
}
在循环中转储名称和元素 ID 不会完成任何事情。当没有什么可迭代时,您的应用程序显然会崩溃 - 然后它遍历循环,退出并转到返回 NULL
的最后一行。
我建议你在循环之后转储元素 id,如下所示。使用 debug_backtrace 也可能有帮助:
public function getChildFormBuilder(FormBuilder $formBuilder, $elementId)
{
foreach (new FormBuilderIterator($formBuilder) as $name => $formBuilder) {
if ($name == $elementId) {
return $formBuilder;
}
}
var_dump(__METHOD__);
var_dump($elementId);
var_dump(debug_backtrace());
return;
}
出现此错误是因为您有超过两层的嵌套集合表单,目前任何版本的 sonata-admin 均不支持它。
来自 @rande (owner) and sonata maintainers at issues #262, #1228, #1327 and #1971 :
This is still not supported for now ....
您也可以查看这个旧的 PR #1971,它应该只解决某些用例的问题。
我建议您的解决方案是实施上次打开的 PR #2985 提供的修复程序。
因为 PR 没有合并,所以你需要告诉作曲家加载它而不是当前(不按预期工作)版本。 (参见 composer and VCS)。
希望PR早日合并
在此之前,请随时直接使用它来解决您的问题,就像很多人一样。
更新
最近合并了Pull Request #3553并修复了嵌套集合在> 2 levels (nested in nested)的问题。
要获得固定版本,您必须使用捆绑包的 dev-master
标签(至少来自 commit 926f159 代表 PR 的合并)。
我试过了,它可以很好地满足以下要求:
// composer.json
"require": {
"sonata-project/admin-bundle": "^2.4@dev",
...
},
希望您可以轻松升级捆绑包以获得修复。
更新2
显然,您的作曲家没有接受分支的最后更改。
PR #2739 提供的修复已在 6 天前合并。
要修复最后一个(希望),您需要更改位于 vendor/sonata-project/admin-bundle/DependencyInjection/Compiler/AddDependencyCallsCompilerPass
的 AddDepencyCallsCompilerPass
中的一个非常短的代码块。
在第 95 行,替换此行:
$groupDefaults[$resolvedGroupName]['items'][] = $id;
致那些:
$groupDefaults[$resolvedGroupName]['items'][] = array(
'admin' => $id,
'label' => !empty($attributes['label']) ? $attributes['label'] : '',
'route' => '',
'route_params' => array(),
);
就像 PR 所做的那样(这是使其正常工作所需的唯一更改)。
我会手动进行修复,因为它是非常新的,并且在一些 days/weeks、运行 之后执行以下命令:
composer clear-cache
和 composer update sonata-project/admin-bundle
您应该在手动添加修复之前尝试一下,也许会添加更改。
此外,您可以使用我在回答开头给出的关于 composer 和 VCS 的 link 并直接要求修复。这是您自己的欣赏,因为它是目前的解决方案。
最后,请耐心等待,修复将很快合并到稳定版本中。