Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ZF2 Models shared between Modules

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?

like image 708
Benno Avatar asked Feb 26 '13 06:02

Benno


1 Answers

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.

like image 91
Andrew Avatar answered Sep 20 '22 19:09

Andrew