3

I am trying to get a ServiceManager instance in my controller to use a factory for Db\Adapter.

I added to module/Application/config/module.config.php:

'service_manager' => [ 'factories' => [ Adapter::class => AdapterServiceFactory::class, ], ], 

To config/autoload/local.php I added the following lines:

'db' => [ 'driver' => 'Mysqli', 'database' => 'mydb', 'username' => 'myuser', 'password' => 'mypassword', ] 

An now I want to access the ServiceManager in my module/Application/src/Controller/IndexController.php. How do I do that?

I tried $sm = $this->getPluginManager(); without success. If I run $serviceManager->get(Adapter::class) with the PluginManager it gives me an error:

Too few arguments to function Zend\Db\Adapter\Adapter::__construct(), 0 passed in (...)\vendor\zendframework\zend-servicemanager\src\Factory\InvokableFactory.php on line 30 and at least 1 expected 

What can I do, to get a ServiceManager that will get my that Adapter object?


I changed the controller factory from

'controllers' => [ 'factories' => [ Controller\IndexController::class => InvokableFactory::class, ], ], 

to

'controllers' => [ 'factories' => [ Controller\IndexController::class => function(ContainerInterface $serviceManager) { return new Controller\IndexController($serviceManager); }, ], ], 

I also added a getServiceConfig() method to the module.config.php and added a constructor to the IndexController, which receives the ServiceManager. Now I have access inside the controller.

But my question is now: is there a nicer, a more "zend like" way to achieve this?

2 Answers 2

5

Thanks to SO's great related topics I finally found the answer. ServiceManager in ZF3

It seems to be done by using Controller Factories, almost like I did.

Sign up to request clarification or add additional context in comments.

4 Comments

That link gives a good answer and is the right way to do it. On a side note: You don't want to inject the complete service manager. It makes your controller untestable. As you can see in that example, only the EntityManager is injected into the controller.
Thank you. I just did it for testing. Now It's de-coupled in different classes.
In ZF3 you should inject all services. Even you can't access forms directly. Ex. in controller you can't use new Form();.
Yes. I did that for testing purposes. My project injects the tables via constructor using factories. Thank you @HaykManasyan
0

I'm experienced with ZF1 and now I'm learning ZF3, I wanted to do a simple thing: set the DB configuration in the configuration file, and then get the db adapter at the controller. It took me awhile to figure it out as the official documents have millions of options for different customization. So I'm posting my answer to help anyone looking.

1- Add the db credentials in config/autoload/global.php or config/autoload/local.php, like this:

<?php return [ 'db' => [ 'driver' => 'Pdo_Mysql',// can be "Mysqli" or "Pdo_Mysql" or other, refer to this link for the full list: https://docs.zendframework.com/zend-db/adapter/ 'hostname' => 'localhost',// optional 'database' => 'my_test_db', 'username' => 'root', 'password' => 'root', ], ]; 

2- In module/YOUR_MODULE_NAME/config/module.config.php, add this under the controllers factories section:

return [ //... 'controllers' => [ 'factories' => [ //... // Add these lines Controller\MycontrollernameController::class => function($container) {// $container is actually the service manager return new Controller\MycontrollernameController( $container->get(\Zend\Db\Adapter\Adapter::class) );// this will pass the db adapter to the controller's constructor }, //... ] ] //... ]; 

3- Finally, in your controller module/YOUR_MODULE_NAME/src/Controller/MycontrollernameController, you can get and use the db adapter:

<?php namespace Application\Controller; use Zend\Mvc\Controller\AbstractActionController; use Zend\View\Model\ViewModel; use Zend\Db\Adapter\Adapter; class MycontrollernameController extends AbstractActionController { private $db; public function __construct($db) { $this->db = $db; } public function indexAction() { $result = $this->db->query('SELECT * FROM `my_table`', Adapter::QUERY_MODE_EXECUTE); echo $result->count();// output total result return new ViewModel(); } } 

There is another way to achieve the same thing by creating a factory for your controller, and inside that factory pass the db adapter to the controller. For beginners trying out ZF3 at hello-world level like me, I think that's too much.

Comments