2
votes

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

2 Answers

4
votes

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.

0
votes

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.