I have an Order entity, which can have multiple LineItem entities associated.
I've created an Admin class for Order and an Admin class for LineItem. But I need the LineItem Admin class to be a child of the Order Admin class.
In the LineItemAdmin class, I've set protected $parentAssociationMapping = 'order';
.
Also, in the OrderAdmin class configureFormFields method, I have added ->add('lineItems', 'sonata_type_model')
.
However, it still doesn't work. The list of line items in the order form are not clickable, so I cannot see how to get from the Order admin form to say the LineItem admin list page.
Are there routes that need to be configured? Are there changes to the lineItems
form field that I need to make?
It's been very difficult to find any good documentation on the Sonata Admin bundle, so any help would be appreciated.
PS. Even going through the SonataAdminBundle code hasn't helped, as the code is very difficult to follow owing to its complexity.
Having just gone through the same problems with undocumented functionality, the only steps you appear to have missed are calling addChild
and configureSideMenu
on the parent OrderAdmin class.
This solution will create a separate page off a sidemenu which will contain the lineItems, they will not be embedded in the OrderAdmin form (I'm not sure that this is possible).
There aren't any routes to be configured, as SonataAdmin handles this for you.
Here's an example parent admin class, using annotations:
namespace YourVendor\YourBundle\Admin;
use JMS\DiExtraBundle\Annotation\Service;
use JMS\DiExtraBundle\Annotation\Tag;
use JMS\DiExtraBundle\Annotation\Inject;
use JMS\DiExtraBundle\Annotation\InjectParams;
use Knp\Menu\ItemInterface as MenuItemInterface;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Admin\AdminInterface;
/**
* @Service("sonata.admin.order")
* @Tag("sonata.admin", attributes={"manager_type"="orm", "group"="Orders", "label"="Orders"})
*/
class OrderAdmin extends Admin
{
/**
* @InjectParams({
* "code" = @Inject("%your.parameters.code%"),
* "class" = @Inject("%your.parameters.class%"),
* "baseControllerName" = @Inject("%your.parameters.controller%"),
* "lineItems" = @Inject("sonata.admin.line_item")
* })
*/
public function __construct($code, $class, $baseControllerName, $lineItems)
{
parent::__construct($code, $class, $baseControllerName);
$this->addChild($lineItems);
}
protected function configureSideMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
{
if (!$childAdmin && !in_array($action, array('edit', 'show'))) { return; }
$admin = $this->isChild() ? $this->getParent() : $this;
$id = $admin->getRequest()->get('id');
$menu->addChild('Show Order', array('uri' => $admin->generateUrl('show', array('id' => $id))));
$menu->addChild('Edit Order', array('uri' => $admin->generateUrl('edit', array('id' => $id))));
$menu->addChild('Line items', array('uri' => $admin->generateUrl('sonata.admin.line_item.list', array('id' => $id))));
}
}
If you use XML or YML for your services you probably won't need the __construct
method as the addChild
calls can go in the service definition.
At the time of writing there's an open issue with the JMS DiExtra Bundle with pull request for a dedicated @Admin annotation which may also avoid this requirement. It's been quiet for a couple of weeks though.