Passing config into model

Hello,

I’m migrating quite a big project from ZF2 to Laminas and I’m nearly there.

In the older version, I have an EmailModel which is accessed by various different controllers in order to send emails, with variables like ‘account name’ @ ‘domain name’ from the config files, which used to be accessed using the ServiceManager with a line like $config = $this->getServiceLocator()->get(‘Configuration’); within the EmailModel.

What is the best way to replace this?

I’ve got all the Controllers working with Factories, that inject the Doctrine Entity manager and the Config into the Controllers when instantiated. The Factory system seems dedicated to Controllers, not Models, and I can’t figure out how to configure the Class’ module.config.php file to replicate the controller injection facility like:

'controllers' => [
    'factories' => [
        Controller\EmailController::class => Factory\EmailControllerFactory::class
    ],
],

Things like the following doesn’t work:

'controllers' => [
    'factories' => [
        Controller\EmailController::class => Factory\EmailControllerFactory::class,
        Model\EmailModel::class => Factory\EmailModelFactory::class,
    ],
],

And this doesn’t work either:

'service_manager' => [
    'factories' => [
        Model\EmailModel::class => Factory\EmailModelFactory::class,
    ],
],

I’d be grateful if someone could tell me either how to inject dependencies into Models, or whether this is completely the wrong approach, and I should be passing the Config variables into the Model as arguments when they are created in a Controller?

I hope that my question makes sense. Thank you,

Tom

Hello and welcome to our forums! :smiley:

This is the correct way to create an object with a factory via the service manager.
Please describe in detail what you mean with „this doesn‘t work“. Where and how do you use this class?

Thank you for the welcome :o)

I thought that defining a factory service manager in the method described would - kind of - intercept new instantiations for, in this example, something like $emailModel = new \Email\Model\EmailModel;

But should I create a new EmailModel (within the Controllers) via the service manager instead? If so, how would I do that? Inject the service manager into the Controller’s construct() function, then use that like the getServiceLocator() in zf2?

No magic is used here, therefore this should not work.

Never inject the service manager into a controller or other classes, the dependencies itself should be injected directly into instances instead.

Unfortunately, I don’t know what Email\Model\EmailModel is or does. I think we can find a good solution when we know more about EmailModel. Can you provide some code?

The whole system is a bit like a cross between a discussion forum and a mailing list. The Email\Model\EmailModel is a big long object that handles all email interactions. For example, when a new comment is made using CommentController it uses EmailModel to send the administrator a notification email. EmailModel is used from quite a few different Controllers to also handle sending out a bulk daily update email to subscribers.

There isn’t much of an EmailController used. the Email module stores all the email templates in the view, then EmailModel puts these together using the Config variables like ‘account name’ @ ‘domain name’, maybe a Comment title & body from a Doctrine entity in the case of the admin notification email and actually sends the email.

The EmailModel handles all the email building & sending for the system and is used by different controllers. I suppose that I could take all the functions out of the EmailModel and put them in their respective Controllers, continuing to use the email templates in Email/view.

Coming from a Doctrine perspective, all the use of Models in the Laminas tutorials & docs deal with database interaction, so it’s tough to see how non-database Models are supposed to work within Laminas.

Use events for this. You have access to the event manager in a controller and you can trigger an event that a comment is added. A listener can listen on this event and send an email, write a log, and more.

And if the channel for sending the notification changes in the future, just add a new listener. The triggers do not have to be changed.

It would be even better if you use the event system in your existing model. For example, when a comment is added to your model, you trigger an event.
Then you are decoupled from controllers and request handlers.

(I will try to add a code example later.)

OK, that makes sense.

Thank you for your time taken to understand my problem, and also for your helpful advice. I’ll look into how to trigger the events from within the Doctrine model.

Looking forward to your example

Can I make a sort of frivolous suggestion without pissing anyone off too much? Change the name from EmailModel to EmailService.For me, models model entities that are more about being than about doing. Services are the workhorses that do the heavy lifting. Where it seems appropriate, you can inject this EmailService into the controller at the factory, and/or use the service in your event listeners to take care of business there, as suggested above.

2 Likes

Good point @davidmintz