I designed my database and cache layer after Zend Framework 1, like this:
class Cache
{
public static function create($adapter, array $params)
{
$class_name = 'Cache_Adapter_' . $adapter;
return new $class_name($params);
}
}
abstract class Cache_Adapter
{
public function __construct(array $params)
{
}
}
class Cache_Adapter_File extends Cache_Adapter
{
// ...
}
Usage example:
// config.php
return array(
'cache' => array(
'adapter' => 'file',
'params' => array(
'path' => '/path',
),
),
);
// bootstrap.php
$dic->cache = Cache::create($config['cache']['adapter'], $config['cache']['params']);
This approach is great, because each cache adapter can have different parameters,
for example, file cache need path to directory where to store cache files.
Then I wanted to create cache adapter for storing data in database and realized that instead of
scalar parameter array, database abstraction class dependency is needed.
Currently database connections are registered in dependency injection container:
// config.php
return array(
'db1' => array(
'adapter' => 'mysql',
'params' => array(
'user' => 'root',
'connect_timeout' => 5,
),
),
'db2' => array(
'adapter' => 'sqlsrv',
'params' => array(
'db' => 'foo',
),
),
);
// bootstrap.php
$dic->db1 = Site:Db::create($config['db1']['adapter'], $config['db1']['params']);
$dic->db2 = Site:Db::create($config['db2']['adapter'], $config['db2']['params']);
So I wanted to ask how in addition to scalar configuration parameter array, zero or more specific dependencies can be passed to cache adapters and this can be done in config.php.
class Cache_Adapter_Db extends Cache_Adapter
{
// Instead of abstract Cache_Adapter::__construct(array $params)
// something like this is needed:
// public function __construct(array $params, Db_Adapter $db)
public function __construct(array $params)
{
}
}
There are 2 steps involved: first your cache adapter should call its parent class in the correct way:
class Cache_Adapter_Db extends Cache_Adapter
{
public function __construct(array $params, Db_Adapter $db)
{
parent::__construct($params);
}
}
Second: your factory class Cache should accept more parameters:
class Cache
{
public static function create($adapter, array $params, $optparams = null )
{
$class_name = 'Cache_Adapter_' . $adapter;
return new $class_name($params, $optparams);
}
}
The config php would look like this:
// config.php
return array(
'db1' => array(
'adapter' => 'mysql',
'params' => array(
'user' => 'root',
'connect_timeout' => 5,
),
),
'db2' => array(
'adapter' => 'sqlsrv',
'params' => array(
'db' => 'foo',
),
'options' => 'extraoption'
),
);
and in bootstrap.php:
$dic->db2 = Site:Db::create(
$config['db2']['adapter'],
$config['db2']['params'],
$config['db2']['options']
);
Related
I am used ZF2 for creating new applications.
We have some issue regarding db connection under controller and model file.
We have put all database credential in "global.php" and "db.local.php" and also fetch db adapter access in our "Module.php" file but we have not fetch database connectivity in controller and model files and don't run query under controller and model.
Here is my code :
**global.php :**
return array(
'db' => array(
'driver'=> 'Pdo',
'dsn'=> 'mysql:dbname=pick_fire;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8'
),
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter'=> 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
**db.local.php :**
<?php
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=pick_fire;host=localhost',
'username' =>'root',
'password' =>'123456',
'driver_options'=> array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8'
),
),
'service_manager' => array(
'aliases' => array(
'db' => 'Zend\Db\Adapter\Adapter',
),
),);
----------------------------------------------
**Module.php :**
public function getServiceConfig()
{
return array(
'factories' => array(
'mail.transport' => function (ServiceManager $serviceManager) {
$config = $serviceManager->get('Config');
$transport = new Smtp();
$transport->setOptions(new SmtpOptions($config['mail']['transport']['options']));
return $transport;
},
),
);
return array(
'factories' => array(
'adapter' => function($serviceManager) {
$config = $serviceManager->get('config');
$dbAdapter = new \Zend\Db\Adapter\Adapter($config['db']);
return $dbAdapter;
}
),
);
}
----------------------------------------------
Please suggest me, how we get fetch database connection and run queries in our controller and model files.
Thank You in Advanced.
In your getServiceConfig() you have two return statements ... the second is never called.
This should work :
**Module.php :**
public function getServiceConfig()
{
return array(
'factories' => array(
'mail.transport' => function (ServiceManager $serviceManager) {
$config = $serviceManager->get('Config');
$transport = new Smtp();
$transport->setOptions(new SmtpOptions($config['mail']['transport']['options']));
return $transport;
},
'adapter' => function($serviceManager) {
$config = $serviceManager->get('config');
$dbAdapter = new \Zend\Db\Adapter\Adapter($config['db']);
return $dbAdapter;
}
),
);
}
I'm getting the following error message with zend framework 2 application:
Missing instance/object for parameter driver for
Zend\Db\Adapter\Adapter::__construct (File:
C:\xampp\zendfw2\ZendSkeletonApplication\vendor\zendframework\zendframework\library\Zend\Di\Di.php:856)
My code is the following:
autoload/local.php:
return array(
'di' => array(
'instance' => array(
'Zend\Db\Adapter\Adapter' => array(
'parameters' => array(
'driver' => 'Zend\Db\Adapter\Driver\Pdo\Pdo',
),
),
'Zend\Db\Adapter\Driver\Pdo\Pdo' => array(
'parameters' => array(
'connection' => 'Zend\Db\Adapter\Driver\Pdo\Connection',
),
),
'Zend\Db\Adapter\Driver\Pdo\Connection' => array(
'parameters' => array(
'connectionInfo' => array(
'dsn' => "mysql:dbname=zendtest;host=localhost",
'username' => 'root',
'password' => '',
'driver_options' => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''),
),
),
),
),
),
);
module.config.php:
return array(
'di' => array(
'Test2\Model\ManagerAbstract' => array(
'parameters' => array(
'adapter' => 'Zend\Db\Adapter\Adapter',
),
),
),
...);
ManagerAbstract.php:
namespace Test2\Model;
use Zend\Db\Adapter\Adapter;
use Zend\Db\Adapter\AdapterAwareInterface;
abstract class ManagerAbstract implements AdapterAwareInterface
{
protected $adapter;
public function setDbAdapter(Adapter $adapter)
{
$this->adapter = $adapter;
}
public function getUserList() {
$sql = new Sql($this->adapter);
$select = $sql->select();
$select->from(array('u'=>'tsrv_user'));
$select->where(array('username' => $username));
$statement = $sql->prepareStatementForSqlObject($select);
$results = $statement->execute();
return $results;
}
}
User.php:
namespace Test2\Model;
class User extends ManagerAbstract
{
public function __construct() {
}
}
And I call it in the Controller like:
$di = new Di();
$model = $di->get('Test2\Model\User');
$model->getUserList();
Can you please help me by pointing out what causes the error message?
I think the definition of the Zend\Db\Adapter\Adapter in your Di configuration isn't correct.
You can find here a correct way how to do that : Zend\Db Adapter instantiation through Zend Framework 2 Di.
I have created Auth and Acl modules using zend-framework2, And these two are working good. Now I want to use these modules multiple times with different configuration.
Basically, I have two sections in my project -
User Section
Admin Section
And both have different session variables and different database tables.
I have Auth configuration file as following (module.config.php) -
return array(
'auth' => array(
'db' => array(
'table' => 'user',
'identity' => 'email',
'credential' => 'password',
'credential_treatment' => array(
'class' => '\My\Common',
'method' => 'encrypt'
),
'status' => array(
'is_enabled = true',
),
),
'view' => array(
'label' => array(
'identity' => 'Email',
),
),
'route' => array(
'login' => 'home',
'logout' => 'home',
),
'whitelist' => array(
'home',
)
),
....
....
);
I want to use the same module for both Admin section and User section, But with different configuration settings, Like different database tables and session variables.
Is it possible to do so or I have to create different modules for different section?
Let me know if you need more details.
Here's an simple approach for your use case. I didn't test it, so expect some typos :)
I hope you get the basic idea. If not, let me know.
config/autoload/auth.global.php
return [
'service_manager' => [
'factories' => [
'YourAuthNamespace\Config' => 'YourAuthNamespace\Service\ConfigServiceFactory',
'YourAuthNamespace\AbstractAuthFactoryFactory' => 'YourAuthNamespace\Service\AbstractAuthFactoryFactory',
],
'abstract_factories' => [
'YourAuthNamespace\AbstractAuthFactoryFactory'
]
]
];
src/YourAuth/Service/AbstractAuthFactoryFactory.php
namespace YourAuth\Service;
class AbstractAuthFactoryFactory implements \Zend\ServiceManager\AbstractFactoryInterface
{
public function canCreateServiceWithName(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
$key = $this->getConfigKeyFromServiceName($name);
$config = $this->getConfig($serviceLocator);
return array_key_exists($key, $config);
}
private function getConfig(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator)
{
return $serviceLocator->get('YourAuthNamespace\Config');
}
public function createServiceWithName(\Zend\ServiceManager\ServiceLocatorInterface $serviceLocator, $name, $requestedName)
{
$key = $this->getConfigKeyFromServiceName($name);
$config = $this->getConfig($serviceLocator);
return new YourAuthClass($config[$key]);
}
private function getConfigKeyFromServiceName($name)
{
return preg_replace('#^YourAuthNamespace\Auth\#i', '', $name);
}
}
src/YourAuth/Service/ConfigServiceFactory.php
namespace YourAuth\Service;
use Zend\ServiceManager\FactoryInterface;
class ConfigServiceFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$config = $serviceLocator->get('Config');
return $config['yourauth'];
}
}
module/MyModuleA/config/module.config.php
return [
'yourauth' => [
'ModuleA' => [ // 'ModuleA' is also the key used by the abstract factory
'db' => [
'table' => 'module_a_auth_table',
// ...
],
'session' => [
'namespace' => 'module_a_session_namespace'
// ...
],
]
],
'service_manager' => array(
'factories' => array(
'MyModuleA\Auth' => function ($sm) {
return $sm->get('YourAuthNamespace\Auth\ModuleA');
}
),
),
];
module/MyModuleA/src/AuthClient.php
namespace MyModuleA;
class AuthClient implements \Zend\ServiceManager\ServiceLocatorAwareInterface
{
public function doSomethingWithAuth()
{
if ($this->getServiceLocator()->get('MyModuleA\Auth')->isAuthorized()) {
// blah...
}
}
}
I have ZF2 tried following, but it does not give any query results with ZF1 works, ZF2 not workings. Is ZF2 database adapters incomplete, left as bug not resolved by ZF2 itself? Cause documentation tells to do so but it simply not working. Does ZF2 adapter works ever?
TestController.php
<?php
namespace Application\Controller;
//namespace Application\Model;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Db\Adapter\Adapter;
use Zend\Debug\Debug;
class TestController extends AbstractActionController {
public function indexAction() {
$sql = "SELECT * FROM stackoverflow";
$statement = $this->adapter->query($sql);
$res = $statement->execute();
Debug::dump( $res );
exit;
}
}
Module.php
<?php
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Router\Http;
class Module {
public function getServiceConfiguration()
{
return array(
'factories' => array(
'adapter' => function($sm) {
$config = $sm->get('config');
$dbAdapter = new \Zend\Db\Adapter\Adapter($config['db']);
return $dbAdapter;
}
),
);
}
}
global.php
<?php
return array(
// 'di' =>array(
// 'instance' =>array(
// 'PDO' => array(
// 'parameters' => array(
// 'dsn' => 'mysql:dbname=mydb;host=localhost',
// 'username' => 'mydb',
// 'password' => '',
// )
// ),
//
// 'User' => array(
// 'parameters' => array(
// 'pdo' => 'PDO'
// )
// )
// )
// ),
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=mydb;host=localhost',
'username' => 'mydb',
'password' => '',
// 'driver_options' => array(
// PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
// ),
),
// 'service_manager' => array(
// 'factories' => array(
// 'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
// ),
// ),
);
The $res is a result set. You can read more about how to extract data from a result set in the ZF manual.
//I just started zf2 myself,but it seems like you can retrieve the data like this.
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
How can I easily implement queries in Zend framework?
Check this document:
Zend Framework Database Quick Start (PDF)
You can use doctrine2
Doctrine project.
There is a module compatibile with ZF3
DoctrineModule.
You can use QueryBuilder that brings creation of query to object manipulation.
You can use the Zend Db Adapter object like so:
$sql = 'SELECT * FROM bugs WHERE bug_id = ?';
$result = $db->fetchAll($sql, 2);
Use Zend_Db and just create a $db Object using Zend_Db Factory Method, and then create SQL Statements using Zend_Db_Select Class and pass the $select SQL Statement to the fetch* (fetchRow, fetchAll...) Methods.
1.Config:
config/autoload/dbAdapter.local.php
<?php
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=name;host=localhost',
'username' => 'root',
'password' => 'root',
),
'service_manager' => array(
'abstract_factories' => array(
'Zend\Db\Adapter\AdapterAbstractServiceFactory',
),
),
);
Implementation:
public function testAction()
{
$username = 'user';
$sql = "SELECT email FROM users WHERE username = ?";
$statement = $this->getDbAdapter()->createStatement($sql, array($username));
$result = $statement->execute()->current();
}
protected function getDbAdapter()
{
if($this->dbAdapter == null) {
$this->dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
}
return $this->dbAdapter;
}
Zend framework has abstract_factories ,it allows us to handle multiple DB queries :
Zend\Db\Adapter\AdapterAbstractServiceFactory
Need to set Service Manager :
'service_manager' => array(
'abstract_factories' => array(
'Zend\Db\Adapter\AdapterAbstractServiceFactory',
),
),
Configure adapters in config/autoload/local.php
db' => array(
'adapters' => array(
'database1' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=userDB;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
etc...
),
),
Configure adapters in config/autoload/global.php
return array(
'db' => array(
'adapters' => array(
'database1' => array(
'username' => 'root',
'password' => '',
),
),
),
);
Call adapters
$dbmanager->get('database1');
Use in Model
use Zend\Db\TableGateway\AbstractTableGateway;
use Zend\Db\Adapter\Adapter;
class UserTable extends AbstractTableGateway
{
protected $table ='user';
public function __invoke(Adapter $adapter)
{
$this->adapter = $adapter;
$this->initialize();
}
public function fetchAll()
{
$resultSet = $this->select();
return $resultSet->toArray();
}
}