ZF2 Models shared between Modules
Asked Answered
C

1

5

I've just started setting up a new ZF2 application for a new project, based off the ZF2 skeleton, and am looking at their tutorial on Models.

tl;dr: how should I share a Model between multiple different modules, by putting it somewhere in a higher level (outside /module)?

We have several modules setup like so:

/
/module/ModuleName
/module/ModuleName/config
/module/ModuleName/src
/module/ModuleName/src/ModuleName

I was just about to setup a folder /module/ModuleName/src/ModuleName/Model/TableName.php, but then I realised: that table will need to be accessed in other Modules as well. So what should I do?

Should I put the Models folder in /module/Model or will that be result in it being treated as a module i.e. site.com/model (based on our current config, it would).

Should I copy and paste the models between places? Should I stick the models back in /vendor/library/Company/Model somewhere? Not quite sure if there's a best practice for this!

Question 2: The tutorial also suggests to use ServiceManager to instantiate the database models to use the same instance. What if I have a module with 5 controllers, with each controller accessing completely separate tables (say 4 tables each)? It seems to me that it would redundantly initialise 16 tables on each page load (for the other controllers in that module). A single table initialisation adds 55ms to the pageload. Is there a way around this?? I'm not sure how I'd move the config to the controller's actions based on what the tutorial does to initialise the tablegateway?

Carbohydrate answered 26/2, 2013 at 6:45 Comment(0)
N
8

1)

You can use any model from any module in your application, so they can be "shared". Fro example you use the ServiceManager to help you grab instances of models (and other classes) in your project.

Service Manager Config:

'factories' => array(
    'AuthService' => function($sm) {
        $auth = new \Zend\Authentication\AuthenticationService();

        return $auth;
    },
    'RoleMapper' => function($sm) {
        $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
        $mapper = new \Application\Mapper\RoleMapper;
        $mapper->setDbAdapter($dbAdapter);
        $mapper->setEntityPrototype(new \Application\Model\Role);
        $mapper->setHydrator(new \Application\Model\RoleHydrator);

        return $mapper;
    },
    'UserMapper' => function($sm) {
        $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
        $mapper = new \MyModule\Mapper\UserMapper;
        $mapper->setDbAdapter($dbAdapter);
        $mapper->setEntityPrototype(new \MyModule\Model\User);
        $mapper->setHydrator($sm->get('UserHydrator'));

        return $mapper;
    },
    ....

As you can see you can have classes from multiple modules defined in there. Usually you would just define a separate ServiceManager config for each module though.

There's nothing to stop you from making an instance of "UserMapper" inside your Application module like this:

Some Controller:

$this->getServiceLocator()->get('UserMapper');
// Or even grab Zend libraries like this
$this->getServiceLocator()->get('AuthService');

The ServiceManager will allow you to grab instances of classes from any of your modules inside any of the others with a problem.

2)

The service manager doesn't actually make an instance of anything until you request it, so there's no overhead as you suggest.

From the example above, there's no instances actually created until you first ask for one:

$this->getServiceLocator()->get('UserMapper'); // instance now created.

If you never ask the service manager for a "RoleMapper" for example, then no instance is created.

Nicks answered 26/2, 2013 at 8:48 Comment(5)
Thanks a lot for your reply Andrew! You're right re: #2, it looks like I was looking at the wrong thing in wincachegrind. Good news! I've seen UserMapper around a lot in a few tutorials - is that just an example, or is it an actual ZF2 thing? In regards to #1: So if I register Manufacturing\Model\WorkflowTable' => function($sm) { .. }, should I then just be able to call $this->getServiceLocator()->get('Manufacturing\Model\WorkflowTable') in any other library? Would it be a more standard practice to have a base module with our models??Carbohydrate
Yes that's the idea, you can call it in any module, all the Service Manager Configs are combined together so so you get anything from all modulesNicks
UserMapper is just an example I used, it's a common scenario for people to use the DataMapper mapper patternNicks
I wouldn't have a base module with all models in there, I would definitely split out into logical modules, ideally to be reused. It depends on the size of project etcNicks
Thanks Andrew! I would generally do the same, although we would have a number of generic models that are used across all modules. e.g. manufacturing would use a workflow model, but so could inventory, ordering or logistics. I'm not going to duplicate the models across different modules...Carbohydrate

© 2022 - 2024 — McMap. All rights reserved.