Matthew, thanks for this elaborate answer. Makes a lot of things clearer
for me.
So, in that case I stick to injecting everything I need. This really bloats
my module.config.php with a lot of redundant stuff and slows me down quite
a bit, but I see your point.
On Tue, Feb 19, 2013 at 5:08 PM, Matthew Weier O'Phinney
wrote:
> On Tue, Feb 19, 2013 at 3:37 AM, roberto blanko
> wrote:
> > one problem drives me nuts, since I started working with ZF2 (never
> worked
> > with Version 1):
> >
> > I'm in need of the service manager all the time. E.g. to access my config
> > in config/autoload/local.php via $sm->get('Config'). I need the service
> > manager everywhere. Controllers, models, you name it. And I don’t want to
> > pass it around by hand, which would make everything ugly.
> >
> > Now I’ve started to implement ServiceLocatorAwareInterface in most
> classes.
>
> Don't.
>
> The best option is to define factories for your classes that inject
> the dependencies for you. When you do that, you no longer have hidden
> dependencies, and you have everything you need up front. When you have
> an instance of the object, it's fully configured.
>
> If you need configuration, you're doing it wrong -- that configuration
> should either be injected, or the objects the configuration
> defines/configures should be injected.
>
> As an example, let's consider a common controller. Let's say it makes
> use of a TableGateway, and you have one or more methods in that
> TableGateway that return a paginator instance. You want to be able to
> specify how many results per page the paginator should use. And for
> insert()/update() operations, you want this information tied to a form
> so that the validation is done correctly; however, you want a
> different form based on the operation (new vs. edit). One element of
> the form needs a DB instance in order to validate.
>
> In ZF1, you'd likely do the following:
>
> * Pull the "db" resource from the bootstrap (actually, a DB adapter).
> * Create a TableGateway instance, and inject the DB adapter.
> * Pull configuration from the registry or the bootstrap.
> * Use that configuration to tell the TableGateway how many items per
> page to return for Paginator instances.
> * You'd create a different form for each operation, and inject the DB
> adapter you pulled.
>
> This is a fair bit of work. And it really, really doesn't belong in
> your controller, any of it.
>
> Let's look at how to do it in ZF2.
>
> First, I'd create a factory for the TableGateway.
>
> 'my-table-gateway' => function ($services) {
> $db = $services->get('db');
> $config = $services->get('config');
> $perPage = isset($config['per_page']) ? $config['per_page'] : 10;
> $tableGateway = new MyTableGateway($db, $perPage);
> return $tableGateway;
> }
>
> Note that in the _factory_ I'm pulling the configuration, but then I'm
> using the values I retrieve from that in order to construct my table
> gateway -- this decouples the TableGateway from my configuration. Also
> note that I'm retrieving the adapter from the service manager --
> dependencies are defined as additional services, and I consume them in
> my factories. How is that dependency defined? As a factory:
>
> 'db' => 'Zend\Db\Adapter\AdapterFactoryService',
>
> Next, let's consider my form and validators. In 2.1, we added the
> ability to define form elements, filters, and validators via plugin
> managers which are managed via the application service manager. This
> means that I can create factories for my forms that consume these. By
> default, if you
>
> 'validators' => array('factories' => array(
> 'MyRecordExists' => function ($validators) {
> $services = $validators->getServiceLocator();
> $db = $services->get('db');
> return new \Zend\Validator\Db\RecordExists(array(
> 'adapter' => $db,
> 'table' => 'some_table',
> 'field' => 'some_field',
> ));
> },
> )),
> 'services' => array('factories' => array(
> 'MyCustomForm' => function($services) {
> $validators = $services->get('ValidatorPluginManager');
> $validatorChain = new \Zend\Validator\ValidatorChain();
> $validatorChain->setPluginManager($validators);
>
> $inputFilterFactory = new \Zend\InputFilter\Factory();
> $inputFilterFactory->setDefaultValidatorChain($validatorChain);
> $inputFilter = new \Zend\InputFilter\InputFilter();
> $inputFilter->setFactory($inputFilterFactory);
>
> return new MyCustomForm('my-custom-form',
> array('input_filter' => $inputFilter));
> },
> )),
>
> In the first case, we've provided a factory for
> Zend\Validator\Db\RecordExists that ensures that it is configured with
> a DB adapter, and the table and field names we require; note that it
> uses its own service name, which allows us to h