[uml] DemoOfMenuTabs

HOT TIP: this content is flagged as highly recommended !

Webel module:

Package/Namespace: 

UML element type:

OOE stereotypes:

Relationships
extends [Generalization]: 

A case study in why you should (nearly always) use private vars and "lazy" instantiation/configuration methods throughout when coding against OOE = Object Oriented Examples = One Of Each

This is an important "anti-example" because it shows you HOW NOT TO DO SOME THINGS in PHP when working with UML-friendly OOE = Object Oriented Examples = One Of Each, and why. Please examine the UML diagram carefully, please read all the UML Comments, please examine the code examples below, and please read all of the related notes. They contain crucial information that explains why OOE = Object Oriented Examples = One Of Each is coded as it is.
UML Diagram
Click on the UML diagram to view it in a lightbox image viewer. You may then zoom in (or just open the image in a new web browser tab using the Download Original link to view large diagrams).

UML modelling domain:

Firstly, this has been named @DemoOfMenuTabs (rather than @DemoMenuTabs) because it does not extend @MenuTabs or implement @IMenuTabs, it just uses an @IMenuTabs.

An @MenuTabs needs at least one @IPageController, which is shared by the top-level path and the 1st tab. In addition, the demo provides page controllers for the 2nd and 3rd tabs.

BTW: You don't usually have to show these additional wrapped classes like DemoPageControllerTab2, they are not "seen" directly by the main wrapper Component @DemoOfMenuTabs, which only "sees" their wrapper Components.


Note how in the reverse-engineered Class DemoOfMenuTabs that PHP UML (PEAR package) is not able to handle the Drupal-coding-style array return type @return \Drupal\ooe\Menu\IMenuItem[] for getMenuItems(), it just leaves it blank (it does not even assign void):
  /**
   *
   * @return \Drupal\ooe\Menu\IMenuItem[]
   */
  public function getMenuItems() {
    return $this->menuTabs->getMenuItems();
  }

This does not matter for (does not ultimately compromise) the analysis «!wrapper» Component @DemoOfMenuTabs; one is free to correct the model to assign a suitable (analysis domain) return type with multiplicity indicator: @IMenuItem[2..*]. (The multiplicity is at least 2, because there is always at least 1 root menu item and 1 default tab menu item.)

Code examples

Firstly we examine the entire DemoOfMenuTabs class. Please pay particular attention to the contructor and to the lack of private vars for the 3 page controllers, but please DO NOT MIMIC IT elsewhere, it is here only to show you what to avoid when coding against OOE = Object Oriented Examples = One Of Each.

namespace Drupal\ooe\Demo\Tabs;
 
use Drupal\ooe\Module\DefaultModuleHelper;
 
class DemoOfMenuTabs extends DefaultModuleHelper {
 
  /**
   * @var \Drupal\ooe\Menu\IMenuTabs 
   */
  private $menuTabs;
 
  /**
   *
   * @return \Drupal\ooe\Menu\IMenuTabs 
   */
  public function getMenuTabs() {
    return $this->menuTabs;
  }
 
  /**
   * Constructor: fetches an IMenuTabs from a factory and configures some tabs.
   * 
   * This example deliberately pragramatically uses on-the-fly creation
   * of page controllers passed directly to the tabs instead of private variables 
   * with lazy creation/configuration configuration methods for the page controllers.
   * This approach is NOT graphical UML-friendly, and is only done here
   * to show you WHAT NOT TO DO when working with OOE.
   * 
   * @param string $module
   *   The machine name of the module
   * @param IFactory $factory
   *   Optional factory; if none given or null a @link DefaultFactory @endlink will be used.
   */
  public function __construct($module, IFactory $factory = null) {
    parent::__construct($module);
    if (! empty($factory)) $this->setFactory($factory);
 
    $path = $module . '/demo/tabs';
    $this->menuTabs = $this->factory()->newMenuTabs(
     $factory, 
     $module, 
     $path, 
     new DemoPageControllerMain(), 
    $this->getModuleDisplayName() . ": Tabs demo");
    $this->menuTabs->newTabMenuItem(new DemoPageControllerTab2(), "Tab2");
    $this->menuTabs->newTabMenuItem(new DemoPageControllerTab3(), "Tab3");
  }
 
  /**
   *
   * @return \Drupal\ooe\Menu\IMenuItem[]
   */
  public function getMenuItems() {
    return $this->menuTabs->getMenuItems();
  }
}

Note how the demo page controllers are created and injected into the tabs pragmatically in the constructor, for such simple demos lazy creators and full private property vars need not always be used, although they are still highly recommended because they are "UML-friendly".

In fact the Property variables $controllerMain, $controllerTab2, $controllerTab3 stereotyped «!local» «!pseudo» that appear in the UML diagram above are "fake" (added by hand in the UML model), and they don't appear anywhere in the reverse-engineered PHP class DemoOfMenuTabs (because the constructor approach showen is not UML-friendly). In other words, I am showing you deliberately here HOW NOT TO DO IT when coding against OOE = Object Oriented Examples = One Of Each


As used within OoeBridge:

  /**
   *
   * @var \Drupal\ooe\Demo\Tabs\DemoOfMenuTabs
   */
  private $demoOfMenuTabs;
 
  /**
   * @return \Drupal\ooe\Demo\Tabs\DemoOfMenuTabs
   *   Lazily creates and configures a @link DemoOfMenuTabs @endlink (in this case a class without interface suffices)
   */
  protected function demoOfMenuTabs() {
    if (empty($this->demoOfMenuTabs)) {
      $this->demoOfMenuTabs = new DemoOfMenuTabs($this->getModule(),$this->factory());
      $this->demoOfMenuTabs->getMenuTabs()->setWeight(-1);
    }
    return $this->demoOfMenuTabs;
  }
 
 
  /**
   * Delegate for hook_menu().
   * 
   */
  public function menu() {
    $menuItemSet = $this->factory()->newMenuItemSet();
..
   //create, configure, and add other menu items
..
    $menuItemSet->addMenuItems($this->demoOfMenuTabs()->getMenuItems());
..
    return $menuItemSet->get();
  }

Note that in this case (just for this demo) the lazy creation/configuration method demoOfMenuTabs() has returned a class DemoOfMenuTabs, rather than an Interface; for the sake of the demo a short-cut has been taken, but we still in the end operate on an IMenuTabs interface offered through the public getMenuItems() method of DemoOfMenuTabs.

Notes (policies)
Demos
Visit also