2

When i define a custom block with a form, i can use :

class LoremIpsumBlock extends BlockBase {

  public function build() {
    // Return the form @ Form/LoremIpsumBlockForm.php.
    return \Drupal::formBuilder()->getForm('Drupal\loremipsum\Form\LoremIpsumBlockForm');
  }

How can i do the same in my custom block when i have a controller in my custom module ?

The example in documentation are too simple :

class HelloBlock extends BlockBase {

  public function build() {
    return array(
      '#markup' => $this->t('Hello, World!'),
    );
  }    
}

I would like to do the same in the HelloBlock class and display all the tables/html created in the controller. Is it possible or do i have to put controller code in block code ?

3

you can call the controller class inside the custom block,

check this below example,

Controller:

   <?php

    namespace Drupal\custom_example\Controller;


    class ExampleController {

         public function example(){

           return array(
             '#title' => 'Example',
             '#markup' => 'This is a custom module', 

            );
         }
    }

custom Block: Here, Use the ExampleController like this,

 use Drupal\custom_example\Controller\ExampleController;

ExampleController should be the class name of the Controller

<?php

namespace Drupal\custom_example\Plugin\Block;


use Drupal\Core\Block\BlockBase;
use Drupal\custom_example\Controller\ExampleController;

class CustomBlock extends BlockBase {

  public function build() {

     $controller_variable = new ExampleController;
     $rendering_in_block = $controller_variable->example();
     return $rendering_in_block;

  }

}

Create the new instance using the class name and call the function in the block

  • Perfect, it is exactly what i was looking for : a complete working example. – Sébastien Gicquel Sep 13 '17 at 8:12
5

@4k4 is correct in their answer that it is preferable to refactor the shared code into a separate class (probably a service).

However, if that is not an option (because you are building on core or contributed code that you cannot change) it is still possible to re-use the output of a controller that uses dependency injection (DI). To do so, inject the class_resolver service into your block and use it to get a controller object. Your block code would look something like this:

<?php

namespace Drupal\my_module\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\DependencyInjection\ClassResolverInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Provides a custom block containing the output of a controller.
 *
 * @Block(
 *  id = "controller_block",
 *  admin_label = @Translation("Controller block"),
 * )
 */
class ControllerBlock extends BlockBase implements ContainerFactoryPluginInterface {

  /**
   * Class Resolver service.
   *
   * @var \Drupal\Core\DependencyInjection\ClassResolverInterface
   */
  protected $classResolver;

  /**
   * Constructs a new ControllerBlock object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param string $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
   *   The class resolver service.
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    ClassResolverInterface $class_resolver
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
    $this->classResolver = $class_resolver;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('class_resolver')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function build() {
    // Assuming that \Drupal\my_module\Controller\MyController::build is a
    // public function that returns the controller output.
    $controller = $this->classResolver->getInstanceFromDefinition('\Drupal\my_module\Controller\MyController');
    return $controller->build();
  }

}
3

A controller depends on a request and route match. In simple cases you can treat the controller like a normal class, but more complex controllers with DI and route arguments will fail. You should refactor the code so that the shared content of the controller and block is built in a different place both have access to, like this is the case in your block example, where this is a form.

  • That "more complex controllers with DI and route arguments will fail" is only true if you simply use the new keyword to instantiate the controller class. See my answer for a solution that will work for controllers with DI. – marcvangend Apr 30 '18 at 11:01
  • @marcvangend, great answer. The OP said, "when i have a controller in my custom module", so I suggested to refactor the code. If refactoring is not an option, I agree, your answer is the best approach. – 4k4 Apr 30 '18 at 12:55
  • @marcvangend, on second thought you have to be careful which dependencies you pull from the class resolver. A controller has a different context than a block. So in general I would first try to refactor the code and by doing this enforce the proper handling of these dependencies. – 4k4 Apr 30 '18 at 13:22
  • Thanks for the feedback, I totally agree. My answer is not the recommended approach because of the reasons you mention. Also, controllers are not meant to be reused this way; a controller is not considered an API. That means the developers who maintain the code could decide it needs refactoring and unintentionally break your code. (Still, it was fun figuring out how to make it work ;-)) – marcvangend Apr 30 '18 at 15:43
1

Use namespace for your controller like:

"use Drupal\your_custom_module\Controller\your_class_name;"

then you can call the function of "your_class_name", where you have generated all the tables/html, inside you build() of Class "HelloBlock" .

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.