0

We are trying to recreate https://www.drupal.org/project/menu_editor for Drupal 8. So our idea is to extend MenuForm and then override the form in our own way to achieve what menu_editor for Drupal 7 provides.

We created a custom module called menu_editor and there we created a route.

  entity.menu.power_edit_form:
  path: '/admin/structure/menu/manage/power_edit/{menu}'
  defaults:
    _form: '\Drupal\menu_editor\Form\MenuEditor'
    _title_callback: '\Drupal\menu_ui\Controller\MenuController::menuTitle'
  requirements:
    _permission: 'access content'

Inside MenuEditor, we extend MenuForm.

namespace Drupal\menu_editor\Form;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Menu\MenuLinkManagerInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Utility\LinkGeneratorInterface;
use Drupal\menu_link_content\MenuLinkContentStorageInterface;
use Drupal\menu_ui\MenuForm;
use Drupal\system\MenuInterface;

/**
 * Class MenuEditor.
 */
class MenuEditor extends MenuForm {

  var $menu;

  public function __construct(MenuLinkManagerInterface $menu_link_manager, MenuLinkTreeInterface $menu_tree, LinkGeneratorInterface $link_generator, MenuLinkContentStorageInterface $menu_link_content_storage)
 {
   // Trying to inject menu as suggested in https://drupal.stackexchange.com/questions/219431/entity-form-additional-arguments but not sure how we can get menu object over here
   $form_object = \Drupal::entityTypeManager()->getFormObject('menu', 'edit');
   $form_object->setEntity($this->menu);
   parent::__construct($menu_link_manager, $menu_tree, $link_generator, $menu_link_content_storage);
 }

 /**
  * {@inheritdoc}
  */
 public function getFormId() {
   return 'menu_editor';
 }

 /**
  * {@inheritdoc}
  */
 public function buildForm(array $form, FormStateInterface $form_state, MenuInterface $menu = NULL) {
   // Can get menu object over here but not sure how I can pass this in constructor. 
   $this->menu = $menu; 
 }

 /**
  * {@inheritdoc}
  */
 public function submitForm(array &$form, FormStateInterface $form_state) {

   parent::submitForm($form, $form_state);
 }

}

Whenever we are running this code, we get the following error.

TypeError: Argument 1 passed to Drupal\Core\Entity\EntityForm::setEntity() must implement interface Drupal\Core\Entity\EntityInterface, null given

I do understand that using $this in the form will not help, since the constructor is called before, but I am not sure how to accomplish this.

1

Declare the entity form in the route via _entity_form instead of _form:

First add a form handler to the entity type:

mymodule.module

/**
 * Implements hook_entity_type_build().
 */
function mymodule_entity_type_build(array &$entity_types) {
  $entity_types['menu']
    ->setFormClass('poweredit', 'Drupal\mymodule\MyMenuForm');
}

Then add the form handler to the route:

mymodule.routing.yml

entity.menu.power_edit_form:
  path: '/admin/structure/menu/manage/power_edit/{menu}'
  defaults:
    _entity_form: 'menu.poweredit'
    _title_callback: '\Drupal\menu_ui\Controller\MenuController::menuTitle'
  requirements:
    _entity_access: 'menu.update'

Now Drupal upcasts the route parameter to an entity and adds it to the form object when it is instantiated.

This is similar to content entities, only that config entities have no form modes. See How to utilize custom form modes to edit a user entity?

  • Thanks, 4k4 the same thing was done in the menu_ui module but I was unable to understand. It works perfectly. – riju.srk Jul 5 '19 at 8:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.