Creating a service

I created a custom page using a controller within a module, but my controller class has too much code in it. I want to take some code out and have a service handle this functionality. I will then have the controller use that service. The result will be a thin controller and more organised code.

Create a service

In my custom module I need to create the file MODULE.services.yml and provide the data that will register my service with the Drupal service container. The arguments are the services that I will be using in my custom service class, originally used in my controller class. 

services:
  module_name.example_service:
    class: Drupal\module_name\Service\ServiceExampleService
    arguments: ['@menu.link_tree', '@path.alias_manager', '@entity.manager']

I then need to create the class and place it into the src/Service directory within our module:

<?php
/**
 * @file
 * Contains Drupal\module_name\Service\ServicesExampleService.
 */

namespace Drupal\module_name\Service;

use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Menu\MenuLinkTreeInterface;
use Drupal\Core\Path\AliasManagerInterface;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\image\Entity\ImageStyle;
use Symfony\Component\DependencyInjection\ContainerInterface;

class ServicesExampleService implements ContainerInjectionInterface {
  /**
   * The menu tree service.
   *
   * @var \Drupal\Core\Menu\MenuLinkTreeInterface
   */
  protected $menuTree;

  /**
   * The path alias manager.
   *
   * @var \Drupal\Core\Path\AliasManagerInterface
   */
  protected $aliasManager;

  /**
   * The entity manager
   *
   * @var \Drupal\Core\Entity\EntityManagerInterface
   */
  protected $entityManager;

  /**
   * Class constructor.
   */
  public function __construct(MenuLinkTreeInterface $menuTree, AliasManagerInterface $alias_manager, EntityManagerInterface $entity_manager) {
    $this->menuTree = $menuTree;
    $this->aliasManager = $alias_manager;
    $this->entityManager = $entity_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('menu.link_tree'),
      $container->get('path.alias_manager'),
      $container->get('entity.manager')
    );
  }

  /**
   * Sector entities via menu.
   */
  public function sector_entities() {
    // Retrieve a list of nodes for a menu.
    $tree = $this->menuTree->load('menu_name', new \Drupal\Core\Menu\MenuTreeParameters());
    $nodes = array();
    foreach ($tree as $item) {
      $title = $item->link->getTitle();
      $internal_path = $item->link->getUrlObject()->getInternalPath();
      $alias = $this->aliasManager->getAliasByPath('/' . $internal_path);
      $node_storage = $this->entityManager->getStorage('node');
      $nodes[$alias] = $node_storage->load($item->link->getMetaData()['entity_id']);
    }
    return $nodes;
  }

}

The important thing to note above is that my service class implements ContainerInjectionInterface and that allows me to use dependency injection to access the other services I need used in my code - or you can extend ControllerBase instead as that class implements ContainerInjectionInterface and have access to functions that provides like currentUser(), config() and state()Now in my controller class I can include this service and have access to all those juicy methods.