PHPUnit 4.8 Mock mysql database interface - php

Good afternoon,
I have a bunch of legacy code that uses the old mysql library (mysql_query($sql) for example) and am trying to test it with PHPUnit (4.8 is the latest that will run on the server for various reasons).
Does anyone know how to mock this database connection so that it can return predetermined results when predetermined queries are run? I have tried using getConnection() (as per the docs here: http://devdocs.io/phpunit~4/database) to no avail.
For example I have this class:
class Raffle {
...
public static function loadAll($filter=""){
//$filter = mysql_real_escape_string($filter); // protect against SQL injection
$raffles = []; // the array to return
$sql = "SELECT * FROM raffles $filter;"; // include the user filter in the query
$query = mysql_query($sql);
//echo mysql_error();
while($row = mysql_fetch_assoc($query)){
$raffles[] = Raffle::loadFromRow($row); // generate the raffe instance and add it to the array
}
return $raffles; // return the array
}
...
}
(The mysql_connect() call is done in a file called db.php which is loaded on every page that it is needed and not in the class file itself.)
Thanks in advance.

For anyone else stuck in this situation I found that building a mock for PDO that contains a fallback to the functional api allowed me to migrate the code to a Testable OO based model while still using the old mysql library under the hood.
For example:
// the basic interfaces (function names taken from PDO
interface DBConnAdapter {
public function query($sql);
}
// since PDO splits connections and statements the adapter should do the same
interface DBQueryAdapter {
public function num_rows();
public function fetch_assoc();
}
...
class DBAdapter implements DBConnAdapter {
public function query($sql){
$query = mysql_query($sql); // run the query using the legacy api
return $query ? new QueryAdapter($query) : false; // return a new query adapter or false.
}
}
...
// an example of a basic mock object to test sql queries being sent to the server (inspired by mockjax :-) )
class DBMock implements DBConnAdapter {
public $queries = []; // array of queries already executed
public $results = []; // array of precomputed results. (key is SQL and value is the returned result (nested array))
public function query($sql) {
if($this->results[$sql]){
$query = new DBQueryMock($sql, $this->results[$sql]); // a mock of PDOStatement that takes the sql it ran and the results to return
$queries[] = $query; // add the query to the array
return $query; // return the query
}
return false; // we do not know the statement so lets pretend it failed
}
// add a result to the list
public function add_single_result($sql, $result){
// check if the index was set, if not make an array there
if(!isset($this->results[$sql])) $this->results[$sql] = [];
// add the result to the end of the array
$this->results[$sql][] = $result;
// return its index
return count($this->results[$sql]) - 1;
}
}
Admittedly this is not an ideal solution as it requires modifying the code to support the adapter objects and removes some functionality (such as mysql_real_escape_string), but it worked....
If you have a better solution please share :-) Thanks!

Related

When is "an established connection" supposed to be true in CodeIgniter?

Can't figure this one out:
In the DB_driver.php (core system/database)
this is beginning of init function...
/**
* Initialize Database Settings
*
* #return bool
*/
public function initialize()
{
/* If an established connection is available, then there's
* no need to connect and select the database.
*
* Depending on the database driver, conn_id can be either
* boolean TRUE, a resource or an object.
*/
if ($this->conn_id)
{
return TRUE;
}
// ----------------------------------------------------------------
// Connect to the database and set the connection ID
$this->conn_id = $this->db_connect($this->pconnect);
The initialize() is called wihtin CI_Controller so when creating new objects for example like this:
$x = new PartyPooper();
$y = new PartyPooper();
initialize() in the DB_driver is called twice. Nothing strange with that, but I would expect $this->conn_id to be set when creating PartyPooper() object second time ($y)?
When is "an established connection" supposed to be true? (In the example two database connections are made when there would should only be one?)
I'm using the latest database drivers in the development branch: https://github.com/EllisLab/CodeIgniter/tree/develop/system/database
I am using the mysqli-driver with persistant connections of.
UPDATE:
I'm not a huge fan messing with core-files, but I couldn't figure out another solution here. Please tell me if there's a better way of achieving of what I want to do.
I came up with this code (using sessions to handle storing and checking for existing db-connections (of the "subdriver"-object. (mysqli object in my case)):
public function initialize()
{
/* If an established connection is available, then there's
* no need to connect and select the database.
*
* Depending on the database driver, conn_id can be either
* boolean TRUE, a resource or an object.
*/
if ($this->conn_id) {
return TRUE;
}
$conn_session_id_name = 'dbsession_conn';
if (isset($_SESSION[$conn_session_id_name])) {
$sess = $_SESSION[$conn_session_id_name];
// Set connection id object or resourse and return true
// because no more connecting has to be done
if (is_object($sess) || is_resource($sess)) {
$this->conn_id = $sess;
return TRUE;
}
}
// Connect to the database and set the connection ID
$this->conn_id = $this->db_connect($this->pconnect);
// Store conn object or resource etc into session
if (is_object($this->conn_id) || is_resource($this->conn_id)) {
$_SESSION[$conn_session_id_name] = $this->conn_id;
}
// No connection resource? Check if there is a failover else throw an error
if ( ! $this->conn_id)
{
//rest of code as before...
My application got extremly much faster because it used one connection instead of around 60.
But my original question remains:
When is this supposed to be true in the initialize() function?
if ($this->conn_id) {
return TRUE;
}
(I didn't remove it when changing the code because I suppose it has some purpose-but even if I can't figure out which)
UPDAtE2 - clarification:
In a model I have a db select statement that is supposed to return PartyPooper objects:
eg. $res = $q->result('PartyPooper');
This PartyPooper is a controller that stores information about people, like names, years , birthdays etc, but it also handles stuff like calculation of info within the same object.
class PartyPooper extends CI_Controller { .... }
But as I understand from the comments below I should do like this instead?
class PartyPooper extends CI_Controller { .... }
class PartyPooperObject { .... } //Store information about people in this object
eg. $res = $q->result('PartyPooperObject');
This piece of code
if ($this->conn_id) {
return TRUE;
}
just assures that the initialize method is only called once per object.
If it has been called on the current object already, it must not be executed another time.

PHP My SQL Error Strict standards: Resource ID#11 used as offset, casting to integer (11)

my Code
function db_fetch_array($query_id = '')
{
if(!$query_id)
{
$query_id = $this->query_result;
}
if($query_id)
{
// success
$this->row[$query_id] = mysql_fetch_array($query_id);
return $this->row[$query_id];
}
else
{
// failure
return false;
}
}
for starters i would do something like this:
if (empty($query_id))
instead of
if (!$query_id)
since !$query_id does not check for empty strings
Further, the error seems to be an issue with using the $query_id as an array key. You may need to find a different identifier
as per divaka's potential alternative in comments below:
Use something else for a key. You can fetch the result first, then get the id of the row and apply it as a key in you array
In case you want to stack several database connections,
consider linking the database in the constructor and instanciate several of these classes, which you can hold in an array.
Example:
class Database
{
protected $link;
public function __construct($user, $pass, $host) {
$this->link = new Mysqli(/* ... */);
}
public function fetch($query) {
$stmt = $this->link->prepare($query);
/* ... */
}
/* ... */
}
Now have your databases in an array:
$db[0] = new Database('root', 'root', 'server1');
$db[1] = new Database('root', 'root', 'server2');
$db['bigCluster'] = new Database('user01', 'passwd', 'cluster.your.biz');
$result = $db[0]->fetch("SELECT * FROM table");
This way you have way better access, control and debugging is easier.
To say something about your code:
function db_fetch_array($query_id = '') { /* .... */ }
This function accepts an empty parameter, thus, allowing the user to fetch from a non-existent database connection. Which results in an error. Don't allow it!
Even better, typehint it:
public function db_fetch_array(\Mysqli $query_id) { /* .... */ }
Solves all your problems at once!
If you need an it your way tho, try the following, giving you a unique, printable id to use as an array key:
$query_id = md5((string)$query_id);
Have a look at the Zend code style guide and modern PHP design patterns, this will help you to increase your code quality by a few hundred percent.

Php create class function to retrieve data from table

I'm new learner in php OOP, I want to create a class function to get register users info, how can I do that?
class Functions{
public static function getUserInfo($user_id){
$sql = mysql_query("SELECT * FROM members WHERE user_id='".$user_id."'");
$rows = mysql_fetch_array($sql);
if(mysql_num_rows($sql) >= 1){
return $rows;
}
}
}
to echo user's info:
$user = new Functions();
$user->getUserInfo($_SESSION['user_id']);
echo $user->user_email;
I got nuthing output with 'undefined property' message, what is the proper way to create function to retrieve user's info? thanks.
Maybe that?
class Functions{
public static function getUserInfo($user_id){
if(empty($user_id)) {
return null;
}
// connect to db
$sql = mysql_query("SELECT * FROM members WHERE user_id='".$user_id."' LIMIT 1");
if(mysql_num_rows($sql) > 0){
$row = mysql_fetch_array($sql, MYSQL_ASSOC);
// close connection to db
return $row;
}
// close connection to db
return null;
}
}
$userID = !empty($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : null;
$user = Functions::getUserInfo($userID);
if($user !== null) {
echo $user['user_email'];
}
This is ony example, use mysqli_* or PDO to manage data in database.
mysql_fetch_array returns array, not object.
$user['user_email'] should work.
In general as you mentioned OOP I would say your code is using classes, but it is not OOP (if I understand correctly how you're going to structure it). What you do is simply wrapping procedural code into a class.
With OOP you need to structure code such a way that it has self-contained objects, so creating "Functions" class containing various utility methods is generally a bad idea. Consider e.g. creating User object instead.
For database abstraction I would recommend checking PDO (http://www.php.net/manual/en/class.pdo.php).

PHP and PDO class

I am trying to learn OOP and decided to make a class which uses PDO.Here some codes from my class.
class DB extends PDO {
public function _construct($dsn,$user,$pass,$options=""){
$options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
try {
parent::__construct($dsn, $user,$pass,$options);
$this->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
}
public function run($query,$all="",$secure=""){
if(empty($secure)){
$qry=$this->query($query);
}else{
$qry=$this->prepare($query);
$qry->execute($this->cleanup($secure));
}
if($all=="all"){
return $qry->fetchAll(PDO::FETCH_ASSOC);
}else{
return $qry->fetch(PDO::FETCH_ASSOC);
}
}
private function cleanup($secure) {
if(!is_array($secure)) {
if(!empty($secure))
$secure = array($secure);
else
$secure = array();
}
return $secure;
}
public function rowCount($table,$extra=""){
$query="Select count(*) from ".$table;
if(!empty($extra)){
$query="Select count(*) from ".$table." ".$extra;
}
$qry=$this->query($query)->fetchColumn();
return $qry;
}
public function select($table,$extra=""){
$query="Select * from ".$table;
if(!empty($extra)){
$query="Select * from ".$table." ".$extra;
}
return $this->query($query);
}
}
What is difference between following codes why i don't get the same result ?
//usage 1 (it doesnt work that way)
$return =$qry->fetchAll(PDO::FETCH_ASSOC);
return $return;
//usage 2 (it is exactly what i need but i want to learn the difference)
return $qry->fetchAll(PDO::FETCH_ASSOC);
Edit : I realy don't know what I was doing wrong but it seems there is no difference between these usages.They both work now.
This is how I use my method
$result=$db->run("my query","all");
foreach($result as $r){
//
}
In the construct method i use PDO's query method to set character to utf-8 but it does not work. If I use after created a DB object it works.
try {
parent::__construct($dsn, $user,$pass,$options);
$this->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->query("SET NAMES 'UTF8'");
$this->query("SET CHARACTER SET UTF8");
}
last question
//what do u think about this usage.I didnt run accross some thing like this
//all the pdo classes i checked use it just
// return $qry->fetchAll(PDO::FETCH_ASSOC);
//do you think i need to separate "fetchAll" and "fetch"
if($all=="all"){
return $qry->fetchAll(PDO::FETCH_ASSOC);
}else{
return $qry->fetch(PDO::FETCH_ASSOC);
}
Don't extend PDO it's just wrong in so many ways. You should instead use it like your title suggests
class Database
{
protected $pdoInstance;
public function __construct($pdoInstance)
{
$this->pdoInstance = $pdoInstance;
}
public function query($query)
{
$preparedStatement = $this->pdoInstance->prepare();
/* bla bla bla */
}
}
This code makes a lot more sense, and is a much better example of good object oriented programming. (It still makes me cringe however, but it's a good start)
First of all, such a good questions can be rarely seen here.
Very few people understand the need of an abstraction class upon PDO.
So, here are some suggestions.
Don't make run into single function. it is much more convenient to have separate methods for different result types. Compare
$data = $db->getAll($sql);
$data = $db->run($sql,"all");
$data = $db->getOne($sql);
$data = $db->run($sql,"one");
$data = $db->getCol($sql);
$data = $db->run($sql,"col");
You need to think of the function names. Your "cleanup" function doesn't do any cleanup.
I would use func_get_args() instead.
What is difference between following codes why i don't get the same result ?
There is no difference
$return = $qry->fetchAll(PDO::FETCH_ASSOC);
return $return;
should work. Define "it doesnt work".
In the construct method i use PDO's query method to set character to utf-8 but it does not work.
Although you should set charset in DSN, this one should be working too. Define "not working"
Also I would suggest to create DSN in the constructor, making config file more familiar.
You may wish also to get some ideas from my mysql helper class. Though it is using different approach from prepared statements, it is way more secure than PDO

What is correct syntax for calling a function recursively in php

I have a function which is using recursion to call itself and I need to know the correct syntax for calling itself.
Note: I am using Object oriented programming technique and the function is coming from a class file.
Below is my function
// Generate Unique Activation Code
//*********************************************************************************
public function generateUniqueActivationCode()
{
$mysql = new Mysql();
$string = new String();
$activation_code = $string->generateActivationCode();
// Is Activation Code Unique Check
$sql = "SELECT activation_id FROM ". TABLE_ACTIVATION_CODES ." WHERE activation_code='$activation_code' LIMIT 1";
$query = $mysql->query($sql);
if($mysql->rowCount($query) > 0)
{
// This function is calling itself recursively
return generateUniqueActivationCode(); // <- Is this syntax correct in Oops
}
else
{
return $activation_code;
}
}
Should the code to call it recursively be
return generateUniqueActivationCode();
OR
return $this->generateUniqueActivationCode();
or if something else other than these 2 ways.
Please let me know.
You would need to call it with the $this variable since your function is part of the instance. So:
return $this->generateUniqueActivationCode();
PS: Why not just try both methods and see if it generates any errors?
Recursion is the COMPLETELY WRONG WAY TO SOLVE THIS PROBLEM
Unlike iteration you're filling up the stack, and generating new objects needlessly.
The right way to solve the problem is to generate a random value within a scope which makes duplicates very unlikely, however without some external quantifier (such as a username) to define the scope then iteration is the way to go.
There are further issues with your code - really you should be adding records in the same place where you check for records.
I am using Object oriented programming technique and the function is coming from a class file
Then it's not a function, it's a method.
And your code is susceptibale to SQL injection.
A better solution would be:
class xxxx {
....
public function generateUniqueActivationCode($id)
{
if (!$this->mysql) $this->mysql = new Mysql();
if (!$this->string) $this->string = new String();
$limit=10;
do {
$activation_code = $string->generateActivationCode();
$ins=mysql_escape_string($activation_code);
$sql="INSERT INTO ". TABLE_ACTIVATION_CODES ." (activation_id, activation_code)"
. "VALUES ($id, '$ins)";
$query = $mysql->query($sql);
if (stristr($query->error(), 'duplicate')) {
continue;
}
return $query->error() ? false : $activation_code;
} while (limit--);
return false;
}
} // end class

Categories