2

I'm trying to figure out the best way to structure a custom module that uses the Queue API in D8. I'm new to D8 and a bit rusty with OOP so forgive me if I'm breaking some recommended design pattern here...

I created a single custom module where multiple different queues need to process items differently, but each queue has common functionality that they may need to use between each other. So my question is, should I create an abstract base class that extends QueueWorkerBase, make processItem abstract, and then add common functionality to the base class?

Something like this:

In src/Plugin/QueueWorker/ProcessQueueBase.php

abstract class ProcessQueueBase extends QueueWorkerBase {

  /**
   * @inheritDoc
   */
  abstract public function processItem($data);

  protected function doSomethingCommon(){
    // Some common logic
  }
}

In src/Plugin/QueueWorker/ProcessQueueOne.php

class ProcessQueueOne extends ProcessQueueBase {

  /**
   * @inheritDoc
   */
  public function processItem($data){
    // Do stuff now

    parent::doSomethingCommon();
  }    
}

In src/Plugin/QueueWorker/ProcessQueueTwo.php

class ProcessQueueTwo extends ProcessQueueBase {

  /**
   * @inheritDoc
   */
  public function processItem($data){
    // Do stuff now

    parent::doSomethingCommon();
  }    
}

OR should I create separate classes that all extend QueueWorkerBase and then just create services for the common functionality.

Something like this:

In DoSomethingService.php:

class DoSomethingService {

  public function doSomethingCommon(){
    // Do something
  }

}

In src/Plugin/QueueWorker/ProcessQueueOne.php

class ProcessQueueOne extends QueueWorkerBase {

  /**
   * @inheritDoc
   */
  public function processItem($data){
    // Do stuff

    $do_something = \Drupal::service('mymodule.doSomething');
    $do_something->doSomethingCommon();
  }    
}

In src/Plugin/QueueWorker/ProcessQueueTwo.php

class ProcessQueueTwo extends QueueWorkerBase {

  /**
   * @inheritDoc
   */
  public function processItem($data){
    // Do stuff

    $do_something = \Drupal::service('mymodule.doSomething');
    $do_something ->doSomethingCommon();
  }    
}
4
  • This is a PHP question basically. But if you have classes that share a majority of the same functionality, you would fill in the methods in the abstract class and extend the class, then override (or add) methods you need to alter functionality for.
    – Kevin
    Mar 14, 2019 at 19:52
  • 3
    If you put the common method in a service then it runs in its own class instance which persists during the request. So this depends on whether the common method uses any states and whether they should persist in each plugin instance or in the shared service.
    – 4uk4
    Mar 14, 2019 at 20:46
  • 1
    I'd prefer the latter, but with injecting dependencies. Although Traits are another possibility. If the it's common operations that don't depend on state then a trait could be pretty useful.
    – mradcliffe
    Mar 15, 2019 at 2:03
  • @mradcliffe My plan was to inject the dependencies, but for the sake of simplicity I chose not to write the full code for it.
    – neuquen
    Mar 15, 2019 at 2:38

2 Answers 2

0

I would suggest an abstract base class, but instead of creating another function ::doSomethingCommon, partially implement ProcessQueueBase::processItem and call parent::processItem from the subclasses.

0

Based on the context you provided I would suggest going for an Abstract class or a Trait.

I try to answer this questions when I doubt:

Question Abstract Trait Service
Does doSomethingCommon() relys on QueueWorkerBase methods or properties? Yes Yes No
Is doSomethingCommon() a common functioanlity that may be used by any other class that does not extends from QueueWorkerBase, for example from a Controller or a Form? No Yes Yes
Should I be able to call doSomethingCommon() individually from a function (or Drupal hook) or a global scope? No No Yes
Should I be able to override or alter doSomethingCommon() functionallity in a class? Yes Yes No

Notice that some Yes are in highlighted. That is more of a personal preference on which I would use based on what will be easier to implement, maintain and understand from a quick look to the code.

I hope this helps you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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