0

I'm starting to learn the benefits of ZF2 dependency injection and am a bit confused on how to create a new instance of a model inside a controller.

I know I can use: $this->getServiceLocator()->get('Crumb'), but I've read it's considered an anti-pattern to use the serviceLocator in a controller.

To bring this problem to life: I have a class Breadcrumbs and a class Crumb. It looks similar to this:

class Breadcrumbs
{
    private $crumbs = array();

    public function getCrumbs(){
        return $this->crumbs;
    }

    public function addCrumb(Crumb $crumb){
        $this->crumbs[] = $crumb;
    }
}


class Crumb
{
    private $title;
    private $url;

    public function setTitle($title){
        $this->title = $name;
    }
}


class DetailController extends AbstractActionController
{
    private $breadcrumbs;

    public function __construct(Breadcrumbs $breadcrumbs){
        $this->breadcrumbs = $breadcrumbs;
    }

    public function indexAction(){
        $crumb = new Crumb();  //Option 1
        $crumb = $this->getServiceLocator()->get('Crumb');  //Option 2
        $crumb = ??  //Option 3 ??

        $this->breadcrumbs->addCrumb($crumb);
    }
}

I'm confused how to create the instance of Crumb. If I follow option 1, I can't use a factory to inject any dependencies into Crumb. If I follow option 2, I use the serviceLocator which is an anti-pattern.

Am I missing anything obvious?

Pedro
  • 163
  • 6
  • «*I can't use a factory to inject any dependencies into Crumb*» — what kind of dependencies you need there? Generally speaking, if you need to use a factory to create your object in controller, you would inject factory and invoke it there. But chances are you don't need it. – weirdan Sep 12 '18 at 08:36
  • Well, tbh this is just an example, and both with and without dependencies exist in my application. But if I understand correctly you would rather use 'new Crumb()' than registering it as an invokable in the serviceManager if it does not have any dependencies? – Pedro Sep 12 '18 at 09:07
  • 1
    Well, I would delegate it to a service layer that would handle it as a part of appropriate domain use case, in a kind of hybrid MVC/ADR ([Action-Domain-Responder](https://en.wikipedia.org/wiki/Action%E2%80%93domain%E2%80%93responder)), as to reduce coupling between application and business logic. On the other hand, breadcrumbs do seem to be a presentation concern, so they might be considered a model, but more in a ViewModel sense, as in [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel). That said, for a toy application I would probably go with direct instantiation. – weirdan Sep 12 '18 at 17:41
  • Hi. Just a site note, or if you keep updating ZF2 framework in your application: since version *2.5*, an ActionController's call to *getServiceLocator()* produces a user deprecation warning/error. Then in ZF3 the *getServiceLocator()* method is gone. You may have an eye on how dependencies will work then. [Example.](https://stackoverflow.com/questions/36061210/deprecated-retrieve-service-locator-in-functional-system-zf2) – BenRoob Sep 14 '18 at 07:03

1 Answers1

2

Since your Crumb class is a Model, it's perfectly acceptable to instantiate it in the Controller.

Depending on your use case it may be more appropriate to create the new Crumbs via a Service, e.g. CrumbService->create($data);. You would then inject the Service into the Controller via a Factory, and update your module config accordingly (i.e. ensure your controller is set up to instantiate via a factory rather than as an invokable class.

thewildandy
  • 318
  • 2
  • 8