Welcome to Abdul Malik Ikhsan's Blog

Zend Framework 2 : Setting Default Db Adapter

Posted in Teknologi, Tutorial PHP, Zend Framework 2 by samsonasik on August 28, 2012

The price of flexibility in Zend Framework 2 often push us to setting all ‘manually’. We have to be a creative person, right ? In this post, i want to present you my greatest post ! Simple, but very important because it can reduce your code redundancy in setting up DbAdapter to Your Table Class.


Without this trick, you have to do the following sooooooo extra and redundant code:

'factories'=> array(
    'ModuleName\Model\TableA' =>  function($sm) {
        $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
        $table     = new \ModuleName\Model\TableA($dbAdapter);
        return $table;
    },
    'ModuleName\Model\TableB' =>  function($sm) {
        $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
        $table     = new \ModuleName\Model\TableB($dbAdapter);
        return $table;
    },
    'ModuleName\Model\TableC' =>  function($sm) {
        $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
        $table     = new \ModuleName\Model\TableC($dbAdapter);
        return $table;
    },
),

Do you want to know how to change that to ‘only’ :

'invokables'=>array(
    'ModuleName\Model\TableA' => 'ModuleName\Model\TableA',
    'ModuleName\Model\TableB' => 'ModuleName\Model\TableB',
    'ModuleName\Model\TableC' => 'ModuleName\Model\TableC',
),

I’m sure, very very very sure !!!, you want to know the trick !.

Firstly, you need to create your common service Factory to your need in your application.

namespace ZfCommons\Service;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class CommonServiceFactory implements FactoryInterface
{
    protected $controller;
    
    public function createService(ServiceLocatorInterface $services)
    {
        $serviceLocator = $services->getServiceLocator();
        $dbAdapter      = $serviceLocator->get('Zend\Db\Adapter\Adapter');
        
        $controller = new $this->controller;
        $controller->setDbAdapter($dbAdapter);
        
        return $controller;
    }
    
    //setter controller 
    public function setController($controller)
    {
        $this->controller = $controller;
    }
}

This Service Factory will set your controller and inject a property named $dbAdapter for your controller that will be instantiated. For reduce re-code your function to setDbAdapter(), just create your master controller :

namespace ZfCommons\Controller; 

use Zend\Mvc\Controller\AbstractActionController;

class MasterController extends AbstractActionController
{
    protected $dbAdapter  ;
    
    public function setDbAdapter($db)
    {
        $this->dbAdapter = $db;
    }
}

which all controller that you created can extends.
Next, create your Table Model class :

namespace Test\Model;

use Zend\Db\TableGateway\AbstractTableGateway;
use Zend\Db\Adapter\Adapter;

class TrackTable extends AbstractTableGateway
{
    protected $table ='tracks';
   
    public function __invoke(Adapter $adapter)
    {
        $this->adapter = $adapter;
        $this->initialize();
    }
    
    public function fetchAll()
    {
        $resultSet = $this->select();
        return $resultSet->toArray();
    }
}

Last step, register that in module config :

return array(
/* router */
/* view_manager */
/* di */
'controllers' => array(
    'factories' => array(
         'Test\Controller\Album' => function($sm){
              $commservice = new \ZfCommons\Service\CommonServiceFactory();
              $commservice->setController('\Test\Controller\AlbumController');
              
              return $commservice->createService($sm);  
           },
      ),
),

'service_factory' => array(
    'invokables' => array(
       //register model table classes here....
       'Test\Model\TrackTable' => 'Test\Model\TrackTable'
     ),
),

Finally, test with create your controller which extends your MasterController :

namespace Test\Controller;

use ZfCommons\Controller\MasterController;

class AlbumController extends MasterController
{
    public function indexAction()
    {
        $tracktable =  $this->getServiceLocator()
                            ->get('Test\Model\TrackTable');
        //dbAdapter will automatically getted !
        $tracktable($this->dbAdapter);  
        
        $result = $tractable->fetchAll();
        //just test 😉
        foreach($result as $key=>$row){
            echo $row['song_title'];
        }
    }
}

Done !!!

References :
https://github.com/weierophinney/PhlyContact

Advertisements

10 Responses

Subscribe to comments with RSS.

  1. Dominic Watson said, on October 4, 2012 at 2:38 am

    Not sure if I’m missing something… but are you moving the repetitive code into creating controllers instead?

    I see you swapped this:

    —————–

    ‘ModuleName\Model\TableA’ => function($sm) {
    $dbAdapter = $sm->get(‘Zend\Db\Adapter\Adapter’);
    $table = new \ModuleName\Model\TableA($dbAdapter);
    return $table;
    },

    ‘Test\Controller\Album’ => ‘\Test\Controller\AlbumController’

    $table = $this->getServiceLocator()->get(‘Test\Model\TrackTable’);
    $table->fetchAll();

    ——————

    For this:

    —————–

    + Additional clases and complexity

    ‘ModuleName\Model\TableA’ => ‘ModuleName\Model\TableA’

    ‘Test\Controller\Album’ => function($sm) {
    $commservice = new \ZfCommons\Service\CommonServiceFactory();
    $commservice->setController(‘\Test\Controller\AlbumController’);
    return $commservice->createService($sm);
    },

    $table = $this->getServiceLocator()->get(‘Test\Model\TrackTable’);
    $table($this->dbAdapter);
    $table->fetchAll();

    —————–

    Or did i miss something magical? 😛

    • samsonasik said, on November 13, 2012 at 10:20 am

      Ah, I just found a tricky to do that, add initilizer service so you do not must to do what i do 🙂

      	    'initializers' => array(
      		function ($instance, $sm) {
      		    if ($instance instanceof \Zend\Db\TableGateway\AbstractTableGateway) {
      			$instance->setDbAdapter($sm->get('Zend\Db\Adapter\Adapter'));
      		    }
      		}
      	    ),
      
      • Nickolas said, on November 29, 2012 at 6:13 am

        if you have own base table class then you can do it this way:
        public function __constructor()
        {
        $this->featureSet = new Feature\FeatureSet();
        $this->featureSet->addFeature(new Feature\GlobalAdapterFeature());
        $this->initialize();
        }

        then anywhere you want (bootstrap, config) call
        Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter($adapter);

  2. dev said, on January 17, 2013 at 8:57 pm

    Hi, i have used the following codes in module.config.php.

    ‘initializers’ => array(
    function ($instance, $sm) {
    if ($instance instanceof \Zend\Db\TableGateway\AbstractTableGateway) {
    $instance->setDbAdapter($sm->get(‘Zend\Db\Adapter\Adapter’));
    }
    }
    ),

    then, how can i create adapter object in controller?

  3. […] rainman1983, ich fand den Ansatz hier ganz nett: Zend Framework 2 : Setting Default Db Adapter | Welcome to Abdul Malik Ikhsan’s Blog Bei uns haben wir das aber einfach über das ServiceLocatorAwareInterface und eine […]

  4. Vimal raj said, on July 18, 2013 at 12:44 am

    I found these in documentaion , while using this i am getting an error ‘ No database adapter was found in the static registry. ‘, Can u pls help me

    Setting a static adapter

    In order to utilize this adapter in non-ServiceLocatorAware classes, you can use
    Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter() to set a
    static adapter:

    In config/autoload/database.local.php

    return array(
    ’db’ => array(
    ’driver’ => ’Pdo’,
    ’dsn’ => ’mysql:dbname=zf2tutorial;host=localhost’,
    ),
    ’service_manager’ => array(
    ’factories’ => array(
    ’Zend\Db\Adapter\Adapter’ => function ($serviceManager) {
    $adapterFactory = new Zend\Db\Adapter\AdapterServiceFactory();
    $adapter = $adapterFactory->createService($serviceManager);
    \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter($adapter);
    return $adapter;
    }
    ),
    ),
    );

    The adapter can then later be fetched using Zend\Db\TableGateway\Feature\GlobalAdapterFeature::getStaticAdapter()
    for use in e.g. Zend\Validator\DbRecordExists:

    $validator = new Zend\Validator\Db\RecordExists(
    array(
    ’table’ => ’users’,
    ’field’ => ’emailaddress’,
    ’adapter’ => \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::getStaticAdapter();
    )
    );


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: