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();
}
}
Related
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'm trying to create a ZF2 application with multiple databases. Based on a user, the database should be dynamically set.
Right now I've the following:
database.local.php
return array(
'db' => array(
'adapters' => array (
'master_db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=master_db;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'USERNAME',
'password' => 'PASSWORD'
),
'tentant_db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=tenant_db;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'USERNAME',
'password' => 'PASSWORD'
),
)
),
'service_manager' => array(
'abstract_factories' => array(
'Zend\Db\Adapter\AdapterAbstractServiceFactory',
)
),
);
For test purposes I've created a form that has a method to fetch some data and put it in a select box. The code to get the database connection is shown in the code below.
MyController.php (in some module)
//... some code
public function someAction(){
$dbAdapter = $this->getServiceLocator()->get('tentant_db');
$form = new AddEolConnectorForm($dbAdapter);
$viewModel = new ViewModel(array(
'form' => $form
));
return $viewModel;
}
//... some more code
My question is, how can I dynamically set the dbname for the tentant_db adapter in my controller (or module)?
Thanks for your help.
The config merge event is one of zend newer event's I believe. It triggers when zend is mergin the config array's which is perfect for the problem you are facing since you can override some array key's dynamically.
public function onMergeConfig(ModuleEvent $e)
{
$configListener = $e->getConfigListener();
$config = $configListener->getMergedConfig(false);
// I'm actually not sure if you have the route match here otherwise you may have to
// use some other method to retrieve the url.
$match = $e->getRouteMatch();
switch ($match) {
case 'first-dependency':
$config['db']['adapter'] => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=master_db;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'USERNAME',
'password' => 'PASSWORD',
),
break;
case 'second-dependency':
$config['db']['adapter'] => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=tenant_db;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'USERNAME',
'password' => 'PASSWORD',
),
break;
// Pass the changed configuration back to the listener:
$configListener->setMergedConfig($config);
}
Based on the above answer I've created to following:
Module.php
class Module implements AutoloaderProviderInterface
{
public function init(ModuleManager $moduleManager)
{
$events = $moduleManager->getEventManager();
// Registering a listener at default priority, 1, which will trigger
// after the ConfigListener merges config.
$events->attach(ModuleEvent::EVENT_MERGE_CONFIG, array($this, 'onMergeConfig'));
}
public function onMergeConfig(ModuleEvent $e)
{
$db = $this->getTentantDb();
$configListener = $e->getConfigListener();
$config = $configListener->getMergedConfig(false);
$config['db']['adapters']['tenant_db']['dsn'] = 'mysql:dbname='. $db .';host=localhost';
$configListener->setMergedConfig($config);
}
// Some more code
public function getTenantDb(){
$tenant_db = 'tenant_12345'
return $tenant_db;
}
}
I don't know if it is the best solution, but the above code is working. I think the next steps should be to put the code in a generic module or something so I can access it from all my modules.
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;
}
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']
);
I'm creating abstract models for managing database entities - I already have EntityAbstract, EntitySetAbstract and a ManagerAbstract models. In my ManagerAbstract model I need a Zend/Db/Adapter instance in order to create a Zend\Db\TableGateway.
How could I pull the main instance of the adapter to my ManagerAbstract? In ZF1 I could have achieved this with Zend_Registry.
If this isn't the right way of doing things in ZF2, I would love to hear the correct way to this kind of things.
Thanks!
Use the Dependency Injection Container, Zend\Di. The ZfcUser project does this if you want to poke around in some working code.
Alternatively, the basic approach is something like this (code untested!):
Firstly: configure the DI to inject the database connection information:
config/autoload/local.config.php:
<?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=mydatabasename;host=localhost",
'username' => 'myusername',
'password' => 'mypassword',
'driver_options' => array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''),
),
),
),
),
),
);
Secondly, within your module's module.config.php file, inject the adapter into the mapper:
module/My/config/module.config.php:
<?php
return array(
'di' => array(
// some config info...
'My\Model\ManagerAbstract' => array(
'parameters' => array(
'adapter' => 'Zend\Db\Adapter\Adapter',
),
),
// more config info...
)
);
Finally, ensure that your ManagerAbstract class can receive the injection:
module/My/src/My/Model/ManagerAbstract.php:
<?php
namespace My\Model;
use Zend\Db\Adapter\Adapter;
use Zend\Db\Adapter\AdapterAwareInterface;
abstract class ManagerAbstract implements AdapterAwareInterface
{
/**
* #var Zend\Db\Adapter\Adapter
*/
protected $adapter;
// some code
public function setDbAdapter(Adapter $adapter)
{
$this->adapter = $adapter;
}
// some more code
}
Note that to use any sub-class, you need to retrieve it via the DIC or inject the mapper into the service and then inject the service into the controller (or other service) where you want to use it.