php - Nested collection fields in Sonata Admin (2.3) -


i'm having problems creating form creating course. part of database scheme i'm trying create form:

enter image description here

so i'm trying create course can create sessions , dates (moment) attached session. should this:

enter image description here

in courseadmin class have:

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 "delete" option being displayed                 'delete' => false,                 'delete_options' => array(                     // may otherwise choose put field hide                     'type'         => 'hidden',                     // in case, need fill in options                     'type_options' => array(                         'mapped'   => false,                         'required' => false,                     )                 )             )         ), array(             'edit' => 'inline',             'inline' => 'table',             'sortable' => 'position'         ))     ; } 

in sessionadmin class have:

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 "delete" option being displayed                 'delete' => false,                 'delete_options' => array(                     // may otherwise choose put field hide                     'type'         => 'hidden',                     // in case, need fill in options                     'type_options' => array(                         'mapped'   => false,                         'required' => false,                     )                 )             )         ), array(             'edit' => 'inline',             'inline' => 'table',             'sortable' => 'position'         ))         ; } 

and in momentadmin class have:

protected function configureformfields(formmapper $formmapper) {     $formmapper         ->add('time',      'date',     array('label' => 'datum'))     ; } 

the problem in form when try add moment (date) session following error:

fatalerrorexception: error: call member function getname() on null in /myproject/app/cache/dev/classes.php line 9772

so, can add session when try add moment session i'm getting error ... .

when in file classes.php on rule 9771 , 9772 there is:

$childformbuilder = $this->getchildformbuilder($formbuilder, $elementid); $fielddescription = $admin->getformfielddescription($childformbuilder->getname()); 

the $childformbuilder null.

when @ function this:

public function getchildformbuilder(formbuilder $formbuilder, $elementid) {     foreach (new formbuilderiterator($formbuilder) $name => $formbuilder) {         if ($name == $elementid) {             return $formbuilder;         }     }     return; } 

when var_dump of $name , $elementid this:

public function getchildformbuilder(formbuilder $formbuilder, $elementid) {     foreach (new formbuilderiterator($formbuilder) $name => $formbuilder) {         var_dump("name: " . $name);         var_dump("elementid: " . $elementid);          if ($name == $elementid) {             return $formbuilder;         }     }      die;     return; } 

and push on add new button following picture:

enter image description here

then output:

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 

in entities have __tostring function. example in course entity:

public function __tostring() {     if(!is_null($this->name))     {         return $this->name;     }     else{         return "";     } } 

what problem here? i'm stuck this. i've posted issue on github repo of sonata admin no answers ...

my entities:

course entity:

<?php  namespace studyx\enrolmentbundle\entity;  use doctrine\orm\mapping 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);     }      /**      * 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;     }      /**      * 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;     }      /**      * 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;     }      /**      * 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;     }      /**      * 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;     }      /**      * 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;     }      /**      * 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;     }      /**      * pricekmo      *      * @return string       */     public function getpricekmo()     {         return $this->pricekmo;     }      /**      * 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);     }      /**      * location      *      * @return \doctrine\common\collections\collection       */     public function getlocation()     {         return $this->location;     } } 

session entity:

    <?php  namespace studyx\enrolmentbundle\entity;  use doctrine\orm\mapping 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);     }      /**      * 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;     }      /**      * type      *      * @return string       */     public function gettype()     {         return $this->type;     }      /**      * 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;     }      /**      * course      *      * @return \studyx\enrolmentbundle\entity\course       */     public function getcourse()     {         return $this->course;     } } 

moment entity:

<?php  namespace studyx\enrolmentbundle\entity;  use doctrine\orm\mapping 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;     }      /**      * time      *      * @return \datetime       */     public function gettime()     {         return $this->time;     }      /**      * 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;     }      /**      * session      *      * @return \studyx\enrolmentbundle\entity\session       */     public function getsession()     {         return $this->session;     } } 

update:

i've added var_dumps function getchildformbuilder this:

public function getchildformbuilder(formbuilder $formbuilder, $elementid) {     foreach (new formbuilderiterator($formbuilder) $name => $formbuilder) {         if ($name == $elementid) {             return $formbuilder;         }     }      var_dump(__method__);     var_dump($elementid);     var_dump(debug_backtrace());      return; } 

the result this:

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]               ... 

update 2:

i've changed require in composer.json "sonata-project/admin-bundle": "^2.4@dev" , updated composer. i'm getting error:

contexterrorexception: warning: illegal string offset 'admin' in app/cache/dev/classes.php line 10482

the error in function:

public function getdashboardgroups() {     $groups = $this->admingroups;     foreach ($this->admingroups $name => $admingroup) {         if (isset($admingroup['items'])) {             foreach ($admingroup['items'] $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; } 

the errors in on line : if (''!= $item['admin']) { .

in config.yml have:

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:             items: ~             item_adds:                 - sonata.admin.location     blocks:         -             position: top             class: col-md-12             type: sonata.admin.block.admin_list 

so think function getdashboardgroups called there.

update 3:

in composer.json have following:

"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" 

should update them ^2.4@dev ?

this error occurs because have more 2 level of nested collection forms, , it's not yet supported in release of sonata-admin.

from @rande (owner) , sonata maintainers @ issues #262, #1228, #1327 , #1971 :

this still not supported ....

you can @ old pr #1971 should solve problem use cases only.

the solution propose implement fix provided last opened pr #2985.
because pr not merged, need tell composer load rather current (not-working expected) version. (see composer , vcs).

hope pr merged soon.
until is, feel free fix problem @ moment using directly, several people do.

update

the pull request #3553 has been merged , fix problem of nested collections @ > 2 levels (nested in nested).

to fixed release, must use dev-master tag of bundle (at least commit 926f159 representing merge of pr).

i tried , works following requirement:

// composer.json  "require": {     "sonata-project/admin-bundle": "^2.4@dev",      ... }, 

i hope can upgrade bundle in order fix.

update2

apparently, composer doesn't take last changes of branch.
fix provided pr #2739 has been merged 6 days ago.

to fix last 1 (hope), need change short code block in adddepencycallscompilerpass located in vendor/sonata-project/admin-bundle/dependencyinjection/compiler/adddependencycallscompilerpass.

at line 95, replace line :

$groupdefaults[$resolvedgroupname]['items'][] = $id; 

to ones:

$groupdefaults[$resolvedgroupname]['items'][] = array(     'admin'        => $id,     'label'        => !empty($attributes['label']) ? $attributes['label'] : '',     'route'        => '',     'route_params' => array(), ); 

like it's done pr (it's needed change make working).

i make fix manually because it's new, , after days/weeks, run following commands:

composer clear-cache , composer update sonata-project/admin-bundle

you should try before adding fix manually, maybe changes added.

also, can use link composer , vcs given @ begin of answer , require fix directly. it's @ own appreciation because of it's solution @ moment.

and last, patient, fixes merged in stable releases soon.


Comments

Popular posts from this blog

javascript - jQuery: Add class depending on URL in the best way -

caching - How to check if a url path exists in the service worker cache -

Redirect to a HTTPS version using .htaccess -