I'm upgrading an application that presently runs on ZendFramework1(ZF1) to ZendFramework2(ZF2). I'm having trouble getting DB results to return from the ZF2 connection.
In ZF1 this test works perfectly:
$db = Zend_Db::factory('Pdo_Mssql', array(
'host' => 'ServerNameFromFreeTdsConfig',
'charset' => 'UTF-8',
'username' => 'myUsername',
'password' => 'myPassword',
'dbname' => 'database_name',
'pdoType' => 'dblib'
));
$stmt = $db->prepare("select * from Products");
$stmt->execute();
$result = $stmt->fetchAll();
$stmt->closeCursor();
However, I've been trying this in ZF2 but I'm not really getting anywhere. In my config\autoload\global.php I have:
return array(
'db' => array(
'host' => 'ServerNameFromFreeTdsConfig',
'charset' => 'UTF-8',
'dbname' => 'database_name',
'username' => 'myUsername',
'password' => 'myPassword',
'driver' => 'pdo',
'pdodriver' => 'dblib',
),
);
And in the Module.php file:
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$config = $e->getApplication()->getServiceManager()->get('Configuration');
$dbAdapter = new Adapter($config['db'], new SqlServer());
GlobalAdapterFeature::setStaticAdapter($dbAdapter);
}
Then in the Model\Products.php
class Products extends AbstractTableGateway
{
protected $table;
protected $featureSet;
public function __construct($table = 'Products') {
$this->table = $table;
$this->featureSet = new FeatureSet();
$this->featureSet->addFeature(new GlobalAdapterFeature());
$this->initialize();
}
//Test the connection.
public function getProducts() {
$result = $this->getAdapter()->query("select * from Products", Adapter::QUERY_MODE_EXECUTE);
die(var_dump($result));
}
}
It looks like it is connecting because the "var_dump" above returns a ["fieldCount":protected]=> int(7) which is correct (there are 7 columns in that table). However, it is not returning any results.
What might I need to do to get this to work in ZF2? Do I need to somehow extend Zend\Db\Adapter\Adapter using code from the ZF1 Zend_Db_Adapter_Pdo_Mssql.php file? Or is there some simple solution I'm missing?
Thanks for any insight.
I think you dont need to mention the user name and password
resources.db.adapter = "sqlsrv"
resources.db.host = "localhost\SQLEXPRESS"
resources.db.dbname = "DatabaseName"
resources.db.isDefaultTableAdapter = true
resources.db.driver_options.ReturnDatesAsStrings = true
I ended up writing my own Adapter adopted from the Zend Framework 1 adapter I had working there. If someone comes across this post looking for a solution to the same problem and would like a copy of the code I transposed, let me know. There is quite a lot of code or I'd post it here.
Related
this is the content of the autoload/global.php file :
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=web_builder;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',
),
),
);
this is the content of the autoload/local.php file:
return array(
'db' => array(
'username' => 'DB_User_Name',
'password' => 'DB_Password',
,
); )
this is part of the content of module/Module.php :
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\Db\Adapter\Adapter;
.........
public function getServiceConfig() {
return array(
'factories' => array(
'Application\Controller\UserController' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new Model\StickyNotesTable($dbAdapter);
return $table;
},
),
);
}
Here I really don't understand what this function do, I just copy pasted from an example. If you could explain me what does getServiceConfig function do, I will really appreaciate it.
Finally the controller content:
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Db\Adapter\Adapter;
use Zend\Db\TableGateway\AbstractTableGateway;
use Zend\Db\Sql\Select;
class UserController extends AbstractActionController{
public function __construct(Adapter $adapter) {
$this->adapter = $adapter;
}
public function loginAction(){
// here i just want to a simple select and yes I know queries will be executed
//in Model, but I want to here a simple query.
//For example in Codeigniter I can't do in model, controller, or view as well.
return new ViewModel();
}
The result of all this code is obviously an error:
Catchable fatal error: Argument 1 passed to Application\Controller\UserController::__construct() must be an instance of Zend\Db\Adapter\Adapter, none given, called in C:\xampp\htdocs\zf2\vendor\zendframework\zendframework\library\Zend\ServiceManager\AbstractPluginManager.php on line 170 and defined in C:\xampp\htdocs\zf2\module\Application\src\Application\Controller\UserController.php on line 21
Can someone post an answer to make this database or query stuff work ? thx
I'm building a Website in Cakephp with variable databases.
I did this with the following code:
CONTROLLER:
$db_host = $DB_SET['Project']['db_host']; //From other database
$db_user = $DB_SET['Project']['db_user'];
$db_pass = $DB_SET['Project']['db_pass'];
$db_database = $DB_SET['Project']['db_database'];
ConnectionManager::create("client_db", array(
'datasource' => 'Database/Mysql',
'driver' => 'mysql',
'persistent' => false,
'host' => $db_host,
'login' => $db_user,
'password' => $db_pass,
'database' => $db_database,
'prefix' => '',
'encoding' => 'UTF8',
'port' => '',
));
$DB_LINE = $this->Page->findPage('3');
MODEL:
class Page extends Model {
public $useDbConfig = 'client_db';
function findPage($pagenr) {
$page = $this->find('first', array(
'conditions' => array (
'Page.id' => $pagenr)
));
return $page;
}
}
Now I also need to change of tables in the database on the Fly.
I do this using(Controller):
$tbl_current = array('tbl_cheques', 'tbl_wishes');
$this->Modelname->useTable = $tbl_current[$pageid]; //Getting the pageID from an url parameter.
Everything works fine, only if I don't wait a while before clicking another page I get this error:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Page.fqlkdf' in 'field list'
This because Cake still have the previous table in his Cache.
If I wait a minute and then I change the page it works fine.
Any suggestions for this problem?
Thanks in advance,
AƤron
Like you said, the table info is cached. So you just need to remove that cache:
Cache::clear(false, '_cake_model_');
Or, you can just temporarily disable cache
Configure::write('Cache.disable', false);
I have an application where each subscriber gets their own 'app' folder within their own url eg.
www.domain.com/1234 subscriber1
www.domain.com/2345 subscriber2
now the db connection is configured in a class in config/database.php. I want to be able to change the database used based on the url (eg. /1234 = db_1234).
How would I achieve this?
Thanks
BTW I am using CakePHP 2.0
My previous solution was a load of rubbish. So I thought about attacking the problem from a different angle. My DATABASE_CONFIG class (/app/Config/database.php) now looks like this:
class DATABASE_CONFIG {
public $default = array(
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => '127.0.0.1',
'login' => 'xxxx',
'password' => 'xxxx',
'database' => 'xxxx',
'prefix' => '',
'encoding' => 'utf8',
);
public $site_one = array(
'datasource' => 'Database/Mysql',
'host' => '127.0.0.1',
// ...
);
public $site_two = array(
'datasource' => 'Database/Mysql',
'host' => '127.0.0.1',
// ...
);
public function __construct()
{
if (strpos(env('HTTP_HOST'), 'site_one') !== false) {
// use site_one database config
$this->default = $this->site_one;
// elseif site_two
} elseif (strpos(env('HTTP_HOST'), 'site_two') !== false) {
// use site_two database config
$this->default = $this->site_two;
}
}
}
When Cake loads, the construct is now called automatically, and this sets the 'default' database connection dependent on the host.
Ah I got it now,
I thought DATABASE_CONFIG was called statically so didn't think to use the construct.
www.domain.com/12345678
function __construct() {
// get folder
if(substr(php_sapi_name(), 0, 3) == "cli") {
$j = explode("/", $_SERVER['PWD']);
$this->default['database'] = "sa_".$j[count($j)-1];
} else {
$j = explode("/", $_SERVER['REQUEST_URI']);
$this->default['database'] = "sa_".$j[1];
}
}
but commandline bake must be done in folder eg. 12345678/
I used this in my UserController
require_once 'Zend/Controller/Action.php';
AND
public function processAction()
{
$params = array('host' =>'localhost',
'username' =>'root',
'password' =>'',
'dbname' =>'zend'
);
$DB = new Zend_Db_Adapter_Pdo_Mysql($params);
$request = $this->getRequest();
$data = array('first_name' => $request->getParam('first_name'),
'last_name' => $request->getParam('last_name'),
'user_name' => $request->getParam('user_name'),
'password' => md5($request->getParam('password'))
);
$DB->insert('user', $data);
$this->view->assign('title','Registration Process');
$this->view->assign('description','Registration succes');
}
Which displayed following error. I do not have the php.ini access.
Fatal error: Class 'Zend_Db' not found in D:\xampp\xampp\htdocs\zend-test\zend-demo\application\controllers\UserController.php on line 42
i.e. on this line
$params = Zend_Db::factory('Pdo_Mysql', array(
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'zend'
));
Thanks in advance!
Mangesh
Maybe this will help.
Tutorial on how to setup a working Zend framework
http://usingzendframework.blogspot.com/2007/01/setting-up-zend-framework.html
You need to include all of the Zend libraries you use - not just
equire_once 'Zend/Controller/Action.php';
Also, you need to do what Jurka specified - a much better and cleaner practice.
I would like to write a cake shell to do a nightly backup of my database using mysqldump. I could do this as a shell script, but if I can cram it into a CakePHP shell, then I will get the added benefit of it working across both the development and live server, if I can get it to automagically read my database config settings. I will cron the cake shell and have some peace-of-mind knowing that I have frequent backups of my DB.
In my shell I'm trying to build up a string which starts with "mysqldump --user=" and I'd like to get the username from app/config/database.php. How can I get at the data in database.php?
In cake 2.1 the format has changed to:
App::uses('ConnectionManager', 'Model');
$dataSource = ConnectionManager::getDataSource('default');
$username = $dataSource->config['login'];
The following snippet should do the trick:
App::import('Core', 'ConnectionManager');
$dataSource = ConnectionManager::getDataSource('default');
$username = $dataSource->config['login'];
In CakePHP 3.x the format has changed to -
use Cake\Datasource\ConnectionManager;
$source = ConnectionManager::get('default');
debug($source); #Debugging the result
Result :
object(Cake\Database\Connection) {
'config' => [
'password' => '*****',
'username' => '*****',
'host' => '*****',
'database' => '*****',
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
'log' => false,
'url' => null,
'name' => 'remote'
],
'driver' => object(Cake\Database\Driver\Mysql) {
'connected' => false
},
'transactionLevel' => (int) 0,
'transactionStarted' => false,
'useSavePoints' => false,
'logQueries' => false,
'logger' => null
}
Get the Result :
debug($source->config()); #Accessing the result
Result :
[
'driver' => 'Cake\Database\Driver\Mysql',
'persistent' => false,
'host' => 'localhost',
'username' => 'username',
'password' => 'password',
'database' => 'database',
'encoding' => 'utf8',
'timezone' => 'UTC',
'cacheMetadata' => true,
'quoteIdentifiers' => false,
'log' => false,
'url' => null,
'name' => 'remote'
]
Just for sharing.
For any cakephp project, if using php as cronjob or command line to do large data processing I would build a standalone php script without cakephp, the reason for doing this because cakephp is slow (e.g. read & process 100K records).
To make my life simple I put all my standalone scripts under app/Vendor/myscripts/ (e.g: app/Vendor/myscripts/process.php)
below also the basic code to make sure you use the same database settings in standalone script with cakephp (tested with MySQL)
require_once '/XYZ/app/Config/database.php';
$database = new DATABASE_CONFIG;
try{
$dblink = new PDO('mysql:host='.$database->default['host'].';dbname='.$database->default['database'], $database->default['login'], $database->default['password'], array(PDO::ATTR_PERSISTENT => false));
$dblink->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dblink->exec('SET CHARACTER SET '.$database->default['encoding']);
} catch (Exception $e) {
die('DB Error'. $e->getMessage());
}
Example in controller, Change multi DB for DataSources in CakePHP 2.5.x
App::uses('AppController', 'Controller');
class DemoController extends AppController {
public $uses = array('AppModel', 'GVA21', 'GVA01', 'GVA14', 'GVA24' );
public function test_dbs(){
$this->autoRender=false;
// Load ConnectManager
App::uses('ConnectionManager', 'Model');
// DataSource ['default']
$MDM = $this->GVA14->find('count');
echo "MDM.GVA14\n<br>";
debug($MDM);
// Get DataSource Config DB ['default'] and ['SRL']
$confDeafult = ConnectionManager::$config->default;
$confSrl = ConnectionManager::$config->SRL;
// Change DataSource ['SRL']
ConnectionManager::drop('default');
ConnectionManager::create('default',$confSrl); //<== Is permanet change Find All models Down
// $this->GVA01->setDataSource('SRL'); //<== Is temp change Find model
echo "SRL.GVA14\n<br>";
$SRL = $this->GVA14->find('count');
debug($SRL);
$SRL = $this->GVA01->find('count');
echo "SRL.GVA01\n<br>";
debug($SRL);
$SRL = $this->GVA21->find('count');
echo "SRL.GVA21\n<br>";
debug($SRL);
// Change to DataSource ['default']
debug(ConnectionManager::drop('default'));
ConnectionManager::create('default',$confDeafult); //<== Is permanet change Find All models Down
//$this->GVA01->setDataSource('default'); //<== Is temp change Find model
$MDM = $this->GVA01->find('count');
echo "MDM.GVA01\n<br>";
debug($MDM);
$MDM = $this->GVA21->find('count');
echo "MDM.GVA21\n<br>";
debug($MDM);
////FIN
exit('FIN');
}