All,
I wrote the following wrapper that extends Zend_Db class to provide db connectivity to my entire application. The db connectivity works fine, but it fails to execute queries when invoked from a different class.
class Testapp_DB extends Zend_Db {
//Declare member variables.
public $db = null;
public $db_host = "";
public $db_database = "";
public $db_username = "";
public $db_password = "";
public function __construct()
{
//Read Database Info from Config File
$this->db_host = Testapp_Registry::get('config')->db->mysql->host;
$this->db_database = Testapp_Registry::get('config')->db->mysql->dbname;
$this->db_username = Testapp_Registry::get('config')->db->mysql->username;
$this->db_password = Testapp_Registry::get('config')->db->mysql->password;
$db = Zend_Db::factory('Mysqli', array(
'host' => $this->db_host,
'username' => $this->db_username,
'password' => $this->db_password,
'dbname' => $this->db_database
));
$db->getConnection(); //Works fine
$this->db = $db;
}
}
Trying to execute query in a PHP file that includes Testapp_DB - fails..
<?php
$db = new Testapp_DB();
print_r($db); //I can see the DB object here
$sql = 'SELECT * FROM tb_Log';
$result = $db->fetchAll($sql, 2); //This method fails.. Don't know why. Any ideas?
print_r($result);
?>
Can someone please explain, why the fetchAll method fails?
Thanks
*Zend_Db* doesnt have any method other than factory().
I dont really get, what you are trying to solve this way, but as far as I can see you need to call query() this way
$db->db->query();
Perhaps instead of using your wrapper, try this:
// Note: change your config to have a 'params' entry
$db = Zend_Db::factory(Testapp_Registry::get('config')->db->mysql);
Zend_Db_Table_Abstract::setDefaultAdapter($db);
Zend_Registry::set('database', $db);
// in your config
...mysql.params.host = ...
...mysql.params.dbname = ...
...mysql.params.username = ...
...mysql.params.password = ...
Then, your Zend_Db_Table objects will have connectivity, and in addition you can grab the connection using Zend_Registry::get('database'). And, you'll make only one database connection once per request.
Try to create a SQL file like schema.mysql.sql,
then test it on phpMyAdmin and when it's free of bugs run this code:
$bootstrap = $application->getBootstrap();
$bootstrap->bootstrap(‘db’);
$config = $bootstrap->getResource(‘db’)->getConfig();
$runCommand = “mysql -h “.$config["host"].” -P “.$config["port"].” -u’”.$config["username"].”‘ -p’”.$config["password"].”‘ “.$config["dbname"].” < “.dirname(__FILE__) . ‘/schema.mysql.sql’;
echo $runCommand;
system($runCommand);
Hope this helps! http://www.unexpectedit.com/zend-php/zend-db-exec-a-sql-file
Related
I am using global variable in my function and after research I found that is a bad practice in PHP instead of that I should use dependency injection but I have problem when changing global to dependency injection. What problem about my code? Thanks for help.
update.php (global)
<?php
include 'db_data.php';
class robot{
public function robotUpdate($conn3){
public function robotUpdate($conn3){
global $nasa;
global $id;
$r_update="UPDATE robot_heartbeat SET last_process_id =$id WHERE nasa_id=$nasa";
$robot_u=$conn3->query($r_update);
}
main.php
<?php
include 'db_data.php';
include 'db_sat.php';
$sql = "SELECT * FROM satellite1.show_activity ";
$result=$conn1->query($sql); //get data from db 1
while($row = $result->fetch_assoc()) {
$sql2 = "INSERT INTO analysis_data.show_activity SET
show_activity_id='".$row["id"]."',
game_show_id='".$row["game_show_id"]."',
account_id='".$row["account_id"]."',
account_code='".$row["account_code"]."',
login_id='".$row["login_id"]."',
$result=$conn3->prepare($sql2); //copy data from db1 into db2
$result->execute();
}
$robot_u = new robot();
$nasa = '2';
$id = $row["id"];
$robot_u->robotUpdate($conn3);
I tried:
update.php (Dependency injection)
<?php
include 'db_data.php';
class robot{
public function robotUpdate($conn3,$nasa,$id){
public function robotUpdate($conn3){
$r_update="UPDATE robot_heartbeat SET last_process_id =$id WHERE nasa_id=$nasa";
$robot_u=$conn3->query($r_update);
}
**main.php**(dependency injection)
$robot_u = new robot();
$robot_u->robotUpdate($conn3,$nasa,$id); //call function first
$nasa = '2'; //inject value
$id = $row["id"];
the value is injected during the function call:
$robot_u->robotUpdate($conn3,$nasa,$id);
So swap them around:
$robot_u = new robot();
$nasa = '2'; //inject value
$id = $row["id"];
$robot_u->robotUpdate($conn3,$nasa,$id);
That said, I noticed you pass a db connection into the class, you might want to consider, if you re-use the same connection over and over in the class to add a constructor
function __construct( $db_connection ) {
$this->db_connection = $db_connection;
}
And create a new instance of the class and pass the db connection there
$robot_u = new robot( $conn3 );
And every time in that class when you need your db connection, use $this->db_connection instead of passing $conn3
Three are lots of free resources around PHP OOP on the internet, would suggest reading some of them :-)
So, simply put, I feel like this code should work. Literally at this moment I am just trying to create a PHP class that takes in some information and runs a command against the database. I know the command works so it's not that, it something to do with the scope of my variables.
I'm new to PHP, and it's been interesting to handle.
<?php
require __DIR__ . '/../bin/composer/vendor/autoload.php';
$cx = new Customer();
$cx->WriteCxToDB();
class Customer {
public $database = new medoo([
'database_type'=>'mysql',
'database_name'=>'dbname',
'server'=>'localhost',
'username'=>'dbusername',
'password'=>'dbpassword',
'charset'=>'utf8'
]);
public function WriteCxToDB(){
global $database;
if($database->has("customer", [
"OR"=>[
"username"=>"cxusername",
"email"=>"email#gmail.com"
]
]))
{
echo "User already exists";
}else{
$database->insert("customer", [
"username"=>"username",
"keyword"=>"keyword",
"email"=>"email#gmail.com",
"phone"=>"444-444-4444",
"first_name"=>"First",
"last_name"=>"Last"
]);
echo "User added";
}
echo "Done";
}
}
?>
I am using composer and medoo to do this database entry. I know the database code works because I've ran it on it's own and it runs fine.
What I'm struggling with the seems to be the variable $database in the code. The function call works if I remove that variable from the mix. I feel like I'm just not understanding where I am supposed to declare the variable / how to reference it from within / outside the function. Thanks.
As suggested in the previous example you should be using something like this and pass a db connection into the class, extending a base class would allow reuse of the db connection:
private $database;
public function __construct($db_connection = null){
//do stuff or set db
$this->database = $this->db_connect;
}
OR make a method in the class to do it
private function db_connect(){
return new medoo([
// required
'database_type' => 'mysql',
'database_name' => 'name',
'server' => 'localhost',
'username' => 'your_username',
'password' => 'your_password',
'charset' => 'utf8',
]);
}
to check consider catching the errors. Using a unique or primary key on the DB would be a safer way of doing this otherwise you have to do validation and searching on the DB. Add the keys and check for duplicate errors.
if($database->error()){
//deal with return or pass to logging
}
The problem here is the use of global scope. Instead of:
global $database;
if($database->has("customer",
use
if($this->database->has("customer",
you could also consider instantiating $database in the constructor, i.e.
private $database;
public function __construct() {
$this->database = new medoo([args....
I am using the Cake for connecting multiple databases in a loop with having same database user config. I just use this method for making different connection on the fly. https://stackoverflow.com/a/6058764/1668476
I just use this in a AppController function and then in all my controller with
Here is the function to connect with database on the fly:
//Used for connecting different databases on the fly
function dbConnect($database, $dataSource = 'default', $prefix = 'mycake_') {
ClassRegistry::init('ConnectionManager');
$database = $prefix.$database;
$nds = $dataSource . '_' . $database;
$db = ConnectionManager::getDataSource($dataSource);
$db->setConfig(array('name' => $nds, 'database' => $database, 'persistent' => false));
if($ds = ConnectionManager::create($nds, $db->config)) return $db->config;
return false;
}
Then in eevery controller is just use useDbConfig like:
$newDbConfig = $this->dbConnect($serverConfig);
$this->Summary->useDbConfig = $newDbConfig['name'];
Problem: Problem is when i try to fetch each of the summary table data in foreach loop. Every time it runs it always keep connects with 1st databases only. Here is the loop:
foreach($this->databases as $key=> $database){
$newDbConfig = $this->dbConnect($database);
$this->Summary->useDbConfig = $newDbConfig['name'];
$this->Summary->cacheQueries = false;
$summary = $this->Summary->findAllByPeriod('1');
debug(count($summary));
}
I tried to use clearCache() or connectionManager:drop() but with no success.
Please help!
Call setSource
The property useDbConfig is not the right/best way to change the datasource of an in-use model. To change the data source at run time, call setDataSource, i.e.:
foreach($this->databases as $key=> $database){
$newDbConfig = $this->dbConnect($database);
$this->Summary->setDataSource($newDbConfig['name']);
...
}
I am upgrading my components from Joomla 1.7 to Joomla 3.3 and have to keep the original database. Therefore I need to access the display data from another database as the installation database. I tried a method that I used many times before with Joomla 2.5 but it seems that I cannot get it right this time.
In my model in the getListQuery() method (which overrides the modellist method) I use the following code to access the database from where I want to get my data:
$dbOptions = getDbOptions();
$db = & JDatabase::getInstance($dbOptions);
where the connection details of my old database are contain in $dbOptions.
I continue to use the following code:
$query = $db -> getQuery(true);
$query -> select('*') -> from('table');
return $query;
I do include the following in the beginning:
jimport('joomla.application.component.modellist');
modellist extends JModelLegacy, therefore I do believe that it uses the following:
/libraries/legacy/model/list.php
But it gives me an error that the table newDatabase.table does not exits and therefore the method I am using does not connect to my old database to retrieve the data from oldDatabase.table.
I am unsure about the inclusion of jimport('joomla.application.component.modellist'); though, could be the problem?
Anyone who can help to retrieve the data from my original database?
If old database on same server and active mysql user has access for it you can use such sql query:
$query = $db -> getQuery(true);
$query -> select('*') -> from('old_database.table');
return $query;
If the entire model is just fetching data from the external database you could use JDatabase->setDbo to replace the default database object with your custom one.
public function __construct($config = array())
{
parent::__construct($config);
$options = array();
$options['driver'] = 'mysqli';
$options['host'] = 'localhost';
$options['user'] = 'username';
$options['password'] = 'password';
$options['database'] = 'database';
$options['prefix'] = 'jos_';
$db = JDatabase::getInstance( $options );
parent::setDbo($db);
}
Now you should be able to access the database in getListQuery() just as you would with your default database. E.g.
$db = JFactory::getDbo();
I believe Adam B's code can have some improvement, regarding setting DB.
public function __construct($config = array())
{
$options = array(
'driver' => 'mysqli',
'host' => 'localhost',
'user' => 'username',
'password' => 'password',
'database' => 'database',
'prefix' => 'jos_'
);
//parent construct will handle setting the DB
$config['dbo']=JDatabase::getInstance( $options );
parent::__construct($config);
}
And getting DB: I think JFactory::getDbo(); will give you the wrong DB, you should do:
self:getDbo();
Using Joomla 2.5, this approach worked for me:
$option = array();
$option['driver'] = 'mysql';
$option['host'] = 'localhost';
$option['user'] = 'XXXXXXXX';
$option['password'] = 'XXXXXXXX';
$option['database'] = 'wordpress';
$option['prefix'] = 'jtt_';
$db = JDatabase::getInstance( $option );
$query = "select * from #__categories";
$db->setQuery($query);
I was able to connect to another database just fine.
I have multiple functions, each running their own SQL query that needs to be inside a transaction... I'm using a static $link to save having to pass around links between functions... for example:
function db() {
$user = "username";
$pass = "password";
$db = "database";
$server = "localhost";
static $link;
if(is_null($link)){
$link = #mysql_connect( $server, $user, $pass );
}
mysql_select_db( $db, $link );
return $link;
}
function transactionWrapper($id){
$link = db();
# Start transaction
mysql_query("SET autocommit=0",$link);
# Get name from other function, but keep this function within the ACID transaction by using the same link
$name = getName($id);
mysql_query("UPDATE tbl2 SET name = '{$name}' WHERE id = '2'",$link);
# Commit transaction
mysql_query("COMMIT",$link);
}
function getName($id){
$link = db();
$result = mysql_query("SELECT name FROM user WHERE id = '{$id}'",$link);
return mysql_result($result,0,0);
}
This works brilliantly at the moment... I can have multiple function calls within different files and not have to pass around the $link.
The problem is now I want to do everything in an object for exception handling and I don't know how to replicate the same static variable upon multiple object instances...
I thought it would be something like:
class db{
static $link;
function db(){
# if link is null, create it with mysql_connect, otherwise return the link
}
}
The problem is... a static variable within a function stays alive for an entire page load, but the static link within an object only exists within the object right?
pconnect isn't an option either :P messy stuff
So how can I get around this? using Objects. I couldn't really find anything after googling for so long so I kind of get the impression I'm doing things a little differently to other people. Inside my transaction I have loads of function calls for various things.
I have alot of code as well... about a year of 60 hrs a week so I didn't have an entire application recode in mind! :P
Thanks, I hope someone can help me and I hope someone else stumbles upon this question in the future if it's answered!
If you declare your object at the start of your script (i.e, as a global), it should be alive for as long as your script runs. This is what my basic SQL class looks like:
class SQL_Connection {
var $connection;
function __construct() {
$this->connection = mysql_pconnect(DB_SERVER, DB_USER, DB_PASS) or die(mysql_error());
mysql_select_db(DB_TABLE, $this->connection) or die(mysql_error());
}
function query($query){
return mysql_query($query, $this->connection);
}
}
Then somewhere in you script you would do:
$db = new SQL_Connection;