Dynamic connection to DB in Zend Framework 2 - php

I have 3 type of databases:
Authen DB (fixed address and fixed schema)
Config DB (fixed address and fixed schema)
Service DBs (dynamic address and dynamic schema based on each service)
After users logined and verified via Authen DB.
Based on the information store in Config DB, all actions in ZF2 application relate to the service should be done on the correlative Service DBs.
Does ZF2 support this case? How can I solve this?
Below codes are my global.php and local.php.
global.php
return array(
'db' => array(
// primary database
'driver' => 'Pdo',
'dsn' => 'mysql:host=xxx.xxx.xxx.xxx;dbname=db_authen',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'",
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
),
// other database
'adapters' => array(
'db_config' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:host=yyy.yyy.yyy.yyy;dbname=db_config',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'",
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
),
),
),
),
'service_manager' => array(
// primary database
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
'navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory'
),
// other database
'abstract_factories' => array(
'Zend\Db\Adapter\AdapterAbstractServiceFactory',
),
),
);
local.php
return array(
'db' => array(
// primary database
'username' => '*****',
'password' => '*****',
// other database
'adapters' => array(
'db_config' => array(
'username' => '*****',
'password' => '*****',
),
),
),
);
Thanks,

After you do your authentication against the (statically configured) Auth DB and consult the (statically configured) Config DB for the dynamic information you need for the Service DB, you could probably instantiate yourself the correct DB-adapter for the Service DB, using something like:
// Config from the Config DB, packaged into an array with keys that
// are expected by \Zend\Db\Adapter\Adapter
$config = [
'driver' => 'Pdo_Mysql', // for example
'user' => 'my-dynamically-obtained-user',
'password' => 'my-dynamically-obtained-password',
'database' => 'my-dynamically-obtained-db-name',
// etc
];
$adapter = new \Zend\Db\Adapter\Adapter($config);
// Now use the $adapter to build queries
$statement = $adapter->query('SELECT * FROM `mytable`');
$results = $statement->execute();
// iterate over the results, etc.
Alternatively, you could feed the $adapter into a model object you create that hides the db-specific query details from the consumer.
See ZF2 docs for \Zend\Db\Adapter\Adapter

Related

Zend 2 Framework Multiple Databases

I trying to configure several database connection in my global.php file. I followed this tutorial ( https://samsonasik.wordpress.com/2013/07/27/zend-framework-2-multiple-named-db-adapter-instances-using-adapters-subkey/#comments ) and was able to access the databases over the servicemanager
Now it looks like
//config/autoload/global.php
return array(
'db' => array(
//this is for primary adapter....
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf21_learn;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
//other adapter when it needed...
'adapters' => array(
'db1' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2_staging;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'db2' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2_test;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
),
),
'service_manager' => array(
// for primary db adapter that called
// by $sm->get('Zend\Db\Adapter\Adapter')
'factories' => array(
'Zend\Db\Adapter\Adapter'
=> 'Zend\Db\Adapter\AdapterServiceFactory',
),
// to allow other adapter to be called by
// $sm->get('db1') or $sm->get('db2') based on the adapters config.
'abstract_factories' => array(
'Zend\Db\Adapter\AdapterAbstractServiceFactory',
),
),
);
Now i can access the primary db by $sm->get('Zend\Db\Adapter\Adapter')
and db1 by $sm->get('db1') in the controller.
Now my question : Is it possible to load all adapters in a array so i can loop through them and pic the one i need.

zend framework 2 and sqlserver driver issues

when i try connecting to my sql server database from my zf2 application as shown below,
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'sqlsrv:dbname=album;hostname=192.168.0.20',
'username' => 'user',
'password' => 'pass',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
I get this error,
File:
/usr/local/zend/apache2/htdocs/zf2-tutorial/vendor/zendframework/zendframework/library/Zend/Db/Adapter/Driver/Pdo/Connection.php:289
Message:
Connect Error: could not find driver
Am i missing something here? Or rather this does not work at all on the linux oriented machines ?
Try taking out this line: "// PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''".
Your connection say you are trying to connect to MSSQL and not MySQL.
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'sqlsrv:dbname=album;hostname=192.168.0.20',
'username' => 'user',
'password' => 'pass',
'driver_options' => array(
// PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
I always prep it like this without trouble, using dist files to set the right connection params as you work through deployment:
local config file
'database' => array(
'connection' => array(
'mysql_master' => array(
'driver' => 'Pdo_Mysql',
'host' => 'host',
'dbname' => 'analytics',
'username' => 'user',
'password' => 'pass',
'charset' => 'UTF8',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'",
),
),
),
),
Then in my Module.php, I define such a factory (in the getServiceConfig array):
'Zend\Db\Adapter\Adapter' => function ($sm){
$config = $sm->get('config');
$dbParams = $config['database']['config']['mysql_master'];
$adapter = new \Zend\Db\Adapter\Adapter($dbParams);
return $adapter;
},
Hope this helps. If this doesn't work, something else is going on.. let me know, I can help.
Cheers.
Alex
The problem is that you don't have the necessary driver installed. I had the same problem with postgres, and this solved it for me:
apt-get install php5-pgsql
However, I am not 100% sure what driver must be installed to make Sql Server work. I did read that it's no longer supported. See this: PHP PDO to MS SQL Server on Ubuntu Server. In a nutshell, your best bet is to rather use:
sudo apt-get install php5-sybase
and then connection string:
"dblib:host=sever;dbname=dbname"
From what I gather, that should connect you to a Sql Server database, but again, I can't gaurantee this because I don't have a setup to test it with. Hope that helps...
I hope this helps you some... I'm currently following along to the Zend Framework 2 skeleton application guide. My database parameters needed to be passed in the following way:
'db' => array(
'driver' => 'SQLSRV',
'hostname' => 'SqlServerName',
'Database' => 'SqlDatabaseName',
'uid' => 'UsertoConnectwith',
'pwd' => 'Passwordofusertoconnectwith'
),

Zend Framework 2 - Database connection

Trying to wrap my head around the new concepts of Zend Framework 2.0.
I'm trying to connect to a database, and to get that connection in a controller or model.
Nothing fancy, just the pure connection to run queries against.
So this is my current code:
//module.config.php
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=DBNAME;host=HOSTNAME,
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'USERNAME',
'password' => 'PASSWORD',
),
'service_manager' => array(
'factories' => array(
'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
What am I doing wrong?
Create db.local.php in your ./config/autoload folder and add the following content
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zenBlog;host=localhost',
'username' =>'root',
'password' =>'',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'service_manager' => array(
'aliases' => array(
'db' => 'Zend\Db\Adapter\Adapter',
),
),);
in your controller $this->getServiceLocator()->get('db'); to access to database.
This is how my local.php in config\autoload\local.php looks like.
<?php
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=<dbname>;host=localhost',
'username' => 'root',
'password' => <your password here>,
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'service_manager' => array(
'aliases' => array(
'adapter' => 'Zend\Db\Adapter\Adapter',
),
),);
Now use this to create a database adapter:
$adapter = $this->getServiceLocator()->get('adapter');
Create a sql statetment and put in variable $sql.
Now do this:
$statement = $adapter->createStatement($sql);
$result = $statement->execute();
Hope this helps.

How to connect to database in zendFramework 2

I can't find where to connect to the database in ZF2, where to create the application.ini to setup required data or in the module->bootstrap method, please help
As others have pointed out, you can add something like the following to your config/autoload/global.php or config/autoload/local.php.
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=mydb;host=localhost',
'username' => 'root',
'password' => '',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
Note that it is best practice to add sensitive information (e.g. the password) to the local.php file. The reason is that this file should be ignored by version control software and is ignored by Git by default if you are using the Zend Skeleton Application due to a .gitignore file.
To use the connection, you can fetch the database adapter from the service manager. For instance, you can do the following in a controller action:
public function someAction() {
$dbAdapter = $this->serviceLocator->get('Zend\Db\Adapter\Adapter');
// Do something with the database adapter, e.g.:
$dbAdapter->query('SELECT username FROM user WHERE id = ?', array(37));
}
The manual should get you started on how you can use the database adapter to execute queries; you will probably want to make use of Zend\Db\Sql, so the above is just an example. Note that you would ideally not access the database (i.e. execute database queries) directly within your controllers, but the above is just an example; it is quite easy to inject the database adapter into a Data Access Layer (DAL) or service layer if you are using any of those design patterns.
What happens above is that the Zend\Db\Adapter\AdapterServiceFactory is invoked. This happens because the class implements the Zend\ServiceManager\FactoryInterface, which the service manager checks against (see the service manager's source code for more information).
The Zend\Db\Adapter\AdapterServiceFactory factory fetches the configuration from the service manager and reads the 'db' key. This configuration (as shown in the first code example) is then passed to the Zend\Db\Adapter\Adapter's constructor which configures the instantiated database adapter.
So, all you have to do is to configure your database connection under the db key in a configuration file and fetch it with the Zend\Db\Adapter\Adapter key from the service manager - then the rest is done for you automatically.
EDIT:
Make sure that you have enabled the AdapterServiceFactory in your configuration for the above to work. Provided that you are using the ZendSkeletonApplication, add the below within config/autoload/global.php.
return array(
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
to config ( global.php etc ):
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=mydb;host=localhost',
'username' => 'mydb',
'password' => '',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
Go to diectory : you_application_folder/config/autoload/
in global.php
<?php
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=mydb;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
);
?>
in local.php // save important data here
<?php
return array(
'db' => array(
'username' => '*****',
'password' => '*****',
);
?>

configure multiple databases in zf2

How can I configure (and use) multiple databases in Zend Framework 2? Currently I have this in my global.php:
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=my_db;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'user',
'password' => '******',
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
But I do not see a way to add a second one.
If you look at the Zend\Db\Adapter\AdapterServiceFactory, you'll see that your adapter configuration points to only one key 'db'. Which means that the Adapter that it builds will always use this (unique) configuration key.
I recommend you to create your own factory that would look like this :
namespace Your\Namespace;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\Db\Adapter\Adapter;
class MyAdapterFactory implements FactoryInterface
{
protected $configKey;
public function __construct($key)
{
$this->configKey = $key;
}
public function createService(ServiceLocatorInterface $serviceLocator)
{
$config = $serviceLocator->get('Config');
return new Adapter($config[$this->configKey]);
}
}
In your main module (or any other one), add the following to the Module.php file to declare the adapters factories to the Zend Service Manager:
use Your\Namespace\MyAdapterFactory;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
class Module implements ServiceProviderInterface{
//Previous code
public function getServiceConfig()
{
return array(
'factories' => array(
'myadapter1' => new MyAdapterFactory('dbconfigkey1'),
'myadapter2' => new MyAdapterFactory('dbconfigkey2'),
),
);
}
//...
The global config should now look like:
return array(
'dbconfigkey1' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=my_db;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'user',
'password' => '******',
),
'dbconfigkey2' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=my_db2;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'user',
'password' => '******',
),
);
to use the adapters you need to call them using the Service Manager:
$adapter1=$serviceManager->get('myadapter1');
$adapter2=$serviceManager->get('myadapter2');
As of version 2.2
An Abstract Service Factory is now part of the zf2 Zend\Db module. It is possible to add multiples configuration keys under the 'adapters' sub-key :
'db'=> array(
'adapters'=>array(
'adapter' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=test;host=localhost',
'username' => 'readCredential',
'password' => '****'
),
'adapter2' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=test;host=localhost',
'username' => 'rwCredential',
'password' => '****'
),
)
),
However, the AbstractServiceFactory need to be added "manually" as it isn't so by default :
'service_manager' => array(
'abstract_factories' => array(
'Zend\Db\Adapter\AdapterAbstractServiceFactory',
)
),
The adapters are accessible as previously :
$adapter1=$serviceManager->get('adapter');
$adapter2=$serviceManager->get('adapter2');
From a performance perspective this second approach is better : One object will be instantiated (The abstract factory) to (potentially) create the different adapters. Whereas in the previous approach, one object per configuration was created.
I found much better explaination on https://samsonasik.wordpress.com/2013/07/27/zend-framework-2-multiple-named-db-adapter-instances-using-adapters-subkey/
Zend Framework 2.2 comes with abstract_factories Zend\Db\Adapter\AdapterAbstractServiceFactory that allow us to configure multiple named DB adapter instances. This is step by step to do it :
Register Zend\Db\Adapter\AdapterAbstractServiceFactory at ‘abstract_factories’ type under ‘service_manager’ key.
//config/autoload/global.php
//.... part of config/autoload/global.php
'service_manager' => array(
'abstract_factories' => array(
'Zend\Db\Adapter\AdapterAbstractServiceFactory',
),
),
Configure ‘adapters’ subkey under ‘db’ key at config/autoload/global.php
//config/autoload/global.php
//.... part of config/autoload/global.php
'db' => array(
'adapters' => array(
'db1' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2_staging;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'db2' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2_test;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
),
),
Configure ‘adapters’ subkey under ‘db’ key at config/autoload/local.php
//config/autoload/local.php
return array(
'db' => array(
'adapters' => array(
'db1' => array(
'username' => 'root',
'password' => '',
),
'db2' => array(
'username' => 'other_user',
'password' => 'other_user_passwd',
),
),
),
);
Call adapter using ‘db1’ or ‘db2’ as db adapter from ServiceManager
$sm->get('db1');
$sm->get('db2');
If you need to get $sm->get(‘Zend\Db\Adapter\Adapter’) as primary adapter, ‘db1’ and ‘db2’ as other adapter for specific purpose, then you need to define primary adapter directly under db, so the configuration of config/autoload/global.php will be like the following :
//config/autoload/global.php
return array(
'db' => array(
//this is for primary adapter....
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf21_learn;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
//other adapter when it needed...
'adapters' => array(
'db1' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2_staging;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'db2' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2_test;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
),
),
'service_manager' => array(
// for primary db adapter that called
// by $sm->get('Zend\Db\Adapter\Adapter')
'factories' => array(
'Zend\Db\Adapter\Adapter'
=> 'Zend\Db\Adapter\AdapterServiceFactory',
),
// to allow other adapter to be called by
// $sm->get('db1') or $sm->get('db2') based on the adapters config.
'abstract_factories' => array(
'Zend\Db\Adapter\AdapterAbstractServiceFactory',
),
),
);
The config/autoload/global.local.php should be configured too like the following :
//config/autoload/local.php
return array(
'db' => array(
// for primary db adapter that called
// by $sm->get('Zend\Db\Adapter\Adapter')
'username' => 'root',
'password' => '',
// to allow other adapter to be called by
// $sm->get('db1') or $sm->get('db2') based on the adapters config.
'adapters' => array(
'db1' => array(
'username' => 'root',
'password' => '',
),
'db2' => array(
'username' => 'other_user',
'password' => 'other_user_passwd',
),
),
),
);

Categories