I am working on using PHPUnit/DBUnit to test the interaction with a database. Thus far, I have been unable to get past creatDefaultDBConnection(). The database has already been created in MySQL, and I fairly confident the initial PDO connection is succeeding since I have not received any error messages to convince me otherwise. createDefaultDBConnection() takes the PDO handler and the schema name. I have provided both, yet I consistently get this error:
Argument 1 passed to PHPUnit_Extensions_Database_DefaultTester::__construct() must
implement interface PHPUnit_Extensions_Database_DB_IDatabaseConnection, null given,
called in ..///PHPUnit/Extensions/Database/TestCase.php on line 132 and
defined
Here is the test:
require_once('../includes/file/to/include.php');
class Core extends PHPUnit_Extensions_Database_TestCase
{
static private $pdo = null;
public function getConnection()
{
$pdo = new PDO("mysql:host=localhost;dbname=dbname", 'root', "root");
$this->createDefaultDBConnection($pdo, "dbname");
}
...
}
Any advice would be greatly appreciated.
This issue was fixed by returning $this->createDefaultDBConnection($pdo, "dbname").
thus,
public function getConnection()
{
$pdo = new PDO("mysql:host=localhost;dbname=dbname", 'root', "root");
return $this->createDefaultDBConnection($pdo, "dbname");
}
Noob mistake
Just a suggestion ...
You might want to consider making your connection a static variable so that it can be re-used. :)
static private $pdo;
static private $conn;
final public function getConnection()
{
if (is_null(static::$conn))
{
if (is_null(static::$pdo))
{
static::$pdo = new PDO('mysql:host=localhost;dbname=dbname', 'root', 'root');
}
static::$conn = $this->createDefaultDBConnection(static::$pdo, 'dbname');
}
return static::$conn;
}
I can't comment yet as my lack of reputation. Here is the good suggestion of #bashaus, juts fixing the way static properties should be called. :)
static private $pdo;
static private $conn;
final public function getConnection()
{
if ( is_null( self::$conn ) )
{
if ( is_null( self::$pdo ) )
{
self::$pdo = new PDO( 'mysql:host=localhost;dbname=dbname', 'root', 'root' );
}
self::$conn = $this->createDefaultDBConnection( self::$pdo, 'dbname' );
}
return self::$conn;
}
Related
I was writting a Singleton class of Database connection, but I ran into some problems. Look:
class PDOSingleConnection
{
private static PDO|null $pdo = null;
public function __construct(PDO $pdo)
{
self::$pdo = $pdo;
}
public static function getPDO(
$hostName = 'localhost',
$username = 'root',
$password = '12345'
): PDO
{
if (is_null(self::$pdo)) {
try {
self::$pdo = new PDO("mysql:host=$hostName;", $username, $password);
self::$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
} catch (\PDOException $PDOException) {
throw new \PDOException($PDOException->getMessage());
}
}
return self::$pdo;
}
}
How you can see, I can't test it 'cause I can't mock my dependency(the PDO class).
My first question is: How can I improve this class, so that it is unit testable?
My second question is: I was reading some topics in the community, and I have seen some people saying that "Singletons are bad news". So, Why "Singletons are bad news"? How can I create a single instance of my database connection, without using the Singleton pattern?
Thank you!!
Folks,
Let me preface this by stating that I'm trying to learn OOP so rather than use one of the existing Mysqli abstraction layers out there, I wanted to write my own Class.
I have the class defined in a file, and I'm just trying to get a generic query working before I start writing specific query functions.
<?php
/* Database Config */
define('DB_NAME', 'project');
define('DB_USER', 'foo');
define('DB_PASS', 'bar');
define('DB_HOSTNAME', '127.0.0.1');
class Database {
private $host;
private $user;
private $pw;
private $db;
public $con;
public function __construct($hostname, $user, $pass, $db) {
$this->DB_HOSTNAME = $hostname;
$this->DB_USER = $user;
$this->DB_PASS = $pass;
$this->DB_NAME = $db;
}
public function connect() {
$this->con = new mysqli($this->hostname, $this->user, $this->pass, $this->db)
or die('Database unavailable');
$this->con->set_charset ('utf8');
}
public function query($sql) {
$stmt = $this->con->query($sql);
}
}
// Create a single global instance of the database class
global $DB;
$DB = new Database();
?>
Then I created a simple test.php containing:
<?php
include_once("include/config.inc");
if ($DB) {
$sql = "select user_login, user_name from users where 1 order by user_name, user_login";
$stmt = $DB->query($sql) or die($DB->errno.__LINE__);
$result = $stmt->fetch_array(MYSQLI_ASSOC);
var_dump($result);
}
else die('Database Unavailable');
?>
When I call that page I get
Fatal error: Call to a member function query() on a non-object in /www/htdocs/project/include/db.class.php on line 33
I'm not getting a die from the test page, so I believe it can reach the database, and I know the table holds data and the query works because if I switch to non Class based DB definition I get an array with expected data.
So I'm pretty sure it's a problem I created in the Class, I just can't figure out what it is. Advice please?
Seems your object wasn't created
this is your construct. It means when you create object you need to specify parameters
public function __construct($hostname, $user, $pass, $db)
Do it like this
$DB = new Database('hostname', 'dbuser', 'dbpass', 'db');
Your class is initialized fine, that's not the issue. The issue is that it can't find the query function on con, since you're not calling connect before you call query.
You should add a line inside your query function to call connect if con doesn't yet exist or isn't active, so you don't have to remember to call it before calling query.
i have a question about php.
I was wondering how can i add this code to a new object so i can later just add it to existing code and use it.
<?php
$mysqli = new mysqli("localhost", "root", "", "kooliasi");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
printf ("System status: %s\n", $mysqli->stat());
$mysqli->close();
?>
Thanks !
Make a class for the connection:
class Database{
private static $link = null ;
public static function getConnection ( ) {
if (self :: $link) {
return self :: $link;
}
$dsn = "mysql:dbname=social_network;host=localhost";
$user = "user";
$password = "pass";
self :: $link = new PDO($dsn, $user, $password); //OR mysqli - matter of preference
return self :: $link;
}
}
Then you can get the connection like this:
Database::getConnection();
This is a Singleton Pattern. You could use this if you like, but it is hard to scale - However, I think it will be fine for your needs. It takes a lot of load off your database.
There is a php.ini setting for prepending a file to every script -> http://www.php.net/manual/en/ini.core.php#ini.auto-prepend-file
You can create a db class where you can keep the connection handle. Add functions to the class as needed. For example
class db{
private $link;
public function __construct(){
$this->link = mysqli_connect(DB_SERVER, DB_USER, DB_PASS,DB_NAME);
}
public function __destruct() {
mysqli_close($this->link);
}
public function query($q){
... add code here for the query
}
}
Then to use the class you call:
$db = new db();
$db->query($parameters_you_want_to_pass);
My first real foray into using PHP OOP and PDO extensively. I have finally gotten the script to work, but as you notice in order to do it I had to move the PDO connect into the login function - originally it was just in the __construct(). I do not want to have to open a new PDO connect and this is sloppy. How can I maintain the same connection throughout the whole class?
<?php
class user{
public $id;
public $name;
public $email;
private $password;
public function __construct() {
$DBH = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
public function login($email,$password,$type){
$DBH = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$password_hash = sha1($password);
try{
if ($type != "actives") {
throw new Exception("Type Handling Error");
}
$STH = $DBH->query("SELECT id, email, password FROM $type WHERE email='$email' AND password='$password_hash'");
$STH->setFetchMode(PDO::FETCH_ASSOC);
$row_count = $STH->rowCount();
$row = $STH->fetch();
if($row_count == 1){
session_start();
session_regenerate_id();
$_SESSION['id'] == $row[id];
return true;
}
else{
return false;
}
}
catch (Exception $e) {
echo $e->getMessage();
}
}
public function loggout(){
session_destroy();
setcookie(session_name(), session_id(), 1, '/');
}
Make the database handle a private member within the class:
class user
{
public $id;
public $name;
public $email;
private $password;
private $dbh;
public function __construct(PDO $dbh)
{
$this->dbh = $dbh;
}
public function login($email, $password, $type)
{
$dbh = $this->dbh;
...
}
Usage:
$pdo = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user = new User($pdo);
Sooner or later, you may need the PDO connection object somewhere else in your code(outside your user object). Therefore,
I would suggest to use one class which will provide static method as below to get the PDO connection object everywhere you want.
class Database{
private static $datasource='mysql:host=HOST dbname=DB';
private static $username='USER';
private static $password='PASS';
private static $db;
//make the constructor private and empty so that no code will create an object of this class.
private function __construct(){}
//the main public function which will return the required PDO object
public static function getDB(){
if(!isset(self::$db)){
try{
self::$db=new PDO(self::$datasoure,self::$username,self::$password);
}
catch(PDOExceptin $e)
{
$error=$e->getMessage(); //variable $error can be used in the database_error.php file
//display database error file.
include('database_error.php');
exit();
}
}
return self::$db;
}
}
Then you can use the static method like below any time you want PDO connection
$conn=Database::getDB();
Use ceejayoz' proposal or add a global function which is responsible for establishing the database connection. The function is written as to connect to the database at most 1 time per HTTP request:
function getPDOConnection() {
// Thanks to the static-specifier, this variable will be initialized only once.
static $conn = new PDO("mysql:host=HOST;dbname=DB", "USER", "PASS");
return $conn;
}
This enables you to maintain the same connection in your whole application (but of course you don't have to use the function everywhere). Basically, this is a very simple application of the Singleton pattern. See the documentation of the static specifier/keyword and try to get familiar with the Singleton pattern.
Add your database connection as a parameter in the constructor, So you when you create a new instance from the user class it automatically runs across the instantiated object
The variable $DBH needs to be a member variable of your class.
Below private $password;, add private $DBH; and you're good to go with deleting the new-connection code from your login function.
I don't want to create a discussion about singleton better than static or better than global, etc. I read dozens of questions about similar subjects on SO, but I couldn't come up with an answer to this SPECIFIC question, so I hope someone could now illuminate me by answering this question with one (or more) real simple EXAMPLES, and not just theoretical discussions.
In my app I have the typical DB class to abstract the DB layer and to perform tasks on DB without having to write everywhere in code mysql_connect / mysql_select_db / mysql...
I could write the class either as a STATIC CLASS:
class DB
{
private static $connection = FALSE; //connection to be opened
//DB connection values
private static $server = NULL; private static $usr = NULL; private static $psw = NULL; private static $name = NULL;
public static function init($db_server, $db_usr, $db_psw, $db_name)
{
//simply stores connections values, without opening connection
}
public static function query($query_string)
{
//performs query over alerady opened connection, if not open, it opens connection 1st
}
...
}
OR as a SINGLETON:
class DBSingleton
{
private $inst = NULL;
private $connection = FALSE; //connection to be opened
//DB connection values
private $server = NULL; private $usr = NULL; private $psw = NULL; private $name = NULL;
public static function getInstance($db_server, $db_usr, $db_psw, $db_name)
{
//simply stores connections values, without opening connection
if($inst === NULL)
$this->inst = new DBSingleton();
return $this->inst;
}
private __construct()...
public function query($query_string)
{
//performs query over already opened connection, if connection is not open, it opens connection 1st
}
...
}
Then after in my app if I want to query the DB i could do
//Performing query using static DB object
DB:init(HOST, USR, PSW, DB_NAME);
DB::query("SELECT...");
//Performing query using DB singleton
$temp = DBSingleton::getInstance(HOST, USR, PSW, DB_NAME);
$temp->query("SELECT...");
To me Singleton has got the only advantage to avoid declaring as static each method of the class. I'm sure some of you could give me an EXAMPLE of real advantage of singleton in this specific case. Thanks in advance.
What is wrong with the following (simplified) example:
class Database
{
protected $_connection;
protected $_config;
public function __construct( array $config ) // or other means of passing config vars
{
$this->_config = $config;
}
public function query( $query )
{
// use lazy loading getter
return $this->_getConnection()->query( $query );
}
protected function _getConnection()
{
// lazy load connection
if( $this->_connection === null )
{
$dsn = /* create valid dsn string from $this->_config */;
try
{
$this->_connection = new PDO( $dsn, $this->_config[ 'username' ], $this->_config[ 'password' ] );
}
catch( PDOException $e )
{
/* handle failed connecting */
}
}
return $this->_connection;
}
}
$db1 = new Database( array(
'driver' => 'mysql',
'host' => 'localhost',
'dbname' => 'test',
'username' => 'test_root',
'password' => '**********'
) );
$db2 = new Database( array(
'driver' => 'pgsql',
'host' => '213.222.1.43',
'dbname' => 'otherdb',
'username' => 'otherdb_root',
'password' => '**********'
) );
$someModel = new SomeModel( $db1 );
$someOtherModel = new SomeOtherModel( $db2 );
$yetAnotherModel = new YetAnotherModel( $db2 );
This demonstrates how you can make use of lazy loading connections, and still have flexibility to use different database connections.
The database instances will only connect to their individual connection when an object that consumes one of the instances (in this case one of the models) decides to call a method of the instance.
In my most recent project, I actually went against the "good" design principles by making the database class entirely static. The reason behind this is that I used a lot of caching on PHP objects. Originally I had the database passed in through the constructor of each object as a dependency injection, however I wanted to make sure that the database didn't have to connect unless absolutely necessary. Thus, using a database as a member variable of that object would not have been practical because if you unserialized an object from the cache, you wouldn't want to connect to the database unless you actually performed an operation on it.
So in the end I had only two (public) static functions, Database::fetch() and Database::execute() which would check whether or not it had already connected, and if not, it would connect and perform the query. This way I wouldn't have to worry about deserialization and would connect as seldom as possible. It technically makes unit testing impossible though.
You don't always have to follow every single good practice. But I would still recommend against doing what I did since some would consider it premature optimization.
My advice: STOP using Singleton and static all together.
Why? Because you will insert dependencies that will render your code unusable in other projects, and will not allow to unit test it. Also forget about loose coupling if using singleton.
The alternatives? Dependency Injection.
http://www.potstuck.com/2009/01/08/php-dependency-injection
Making DB library static is certainly shorter and quicker, than doing:
$db = DBSingleton::blabla(); // everytime I need ya
But also, since it is global, tempting to use everywhere.
So, choose other methods if you want clean code... and choose static if you need quick code ;-)
/* Data base*/
class Database
{
/* Database field definition */
private static $_instance; /instance
private $_connection;
private $DB_USER = "database_user_name_here";
private $DB_PASS = "your_password_here";
private $DB_NAME = "your_database_name_here";
private $DB_SERVER = "localhost";
/* Initiate the database connection */
private function __construct()
{
$this->_connection = new mysqli($this->DB_SERVER ,
$this->DB_USER ,
$this->DB_PASS ,
$this->DB_NAME);
/* Test if connection succeeded */
if (mysqli_connect_errno()) {
die("Database connection failed: " .
mysqli_connect_error() .
" (" . mysqli_connect_errno() . ")"
);
}
}
/**
* Instance of the database
* #return Database
*
*/
public static function Instance()
{
if (!self::$_instance) { // If no instance then make one
self::$_instance = new self();
}
return self::$_instance;
}
/**
* Void duplicate connection
*/
private function __clone() { }
/* Return a connection */
public function getConnection()
{
return $this->_connection;
}
}
/** This is how you would use it in a different class.
#var TYPE_NAME $connection */
$db = Database::Instance();
$connection = $db->getConnection();