Im getting a Fatal error: Call to undefined method PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection::prepare() on a phpunit test where I'm preparing a PDO statement. If the default database connection is a copy of the pdo object that successfully connects, wouldn't it have access to its methods?
My Class and the function in question:
class User
{
protected $db;
public function __construct($db)
{
$this->db = $db;
}
public function deleteItem($itemId)
{
$sql = "
DELETE FROM Users WHERE id = ?";
$sth = $this->db->prepare($sql);//this is the failed line works on other tests
return $sth->execute(array($itemId));
}
My Test:
class RosterDBTest extends PHPUnit_Extensions_Database_Testcase
{
public function getConnection()
{
$pdo = new PDO('mysql:host=localhost;dbname=users','root','root');
return $this->createDefaultDBConnection($pdo,"users");
}
public function getDataSet()
{
return $this->createFlatXMLDataset(
dirname(__FILE__) . '/users.xml');
}
public function setup()
{
$this->db = $this->getConnection();
}
public function testRemoveUser()
{
$testUser = new User($this->db);
$expectedUsers = 123;
$testUser->deleteItem(91);
$totalUsers = $testUsers->getAllUsers();
$this->assertEquals( $expectedUsers,count($totalUsers), 'Did not delete User 91' );
}
I've just been stuck on a similar problem where I had my abstract database testcase class. Solved it by changing
public function setup()
{
$this->db = $this->getConnection();
}
to
public function setup()
{
$this->db = $this->getConnection()->getConnection();
}
Not sure if this helps with this but hopefully will help someone.
Related
I tried to do a simple CRUD using a class connectDB to connect to a MySQL database. Then when I try to execute the method delRecipe of the class RecipesModel the system show me an error.
Fatal error: Call to undefined method connectDB::prepare()
Is the right way to call the method prepare()? Why is not recognized?
Here is the code of connectDB (file connectDB.php)
class connectDB {
private $address='localhost';
private $db_name='db-name';
private $user='root';
private $pswd='psswd';
private $sql;
public function __construct() {
$this->sql = new mysqli($this->address,$this->user,$this->pswd,$this->db_name);
if (mysqli_connect_error()) {
die('Error de Conexion: '. mysqli_connect_errno().' - '.mysqli_connect_error());
}
return $this->sql;
}
public function __destruct() {
if(!mysqli_close($this->sql)) {
die('ERROR!:'.$this->sql->error);
}
}
public function execute($query) {
$res = $this->sql->query($query);
if ($res) {
return $res;
}
else {
die('ERROR!:'.$this->sql->error);
}
}
}
And the class that delete the row.
<?php
require_once('connectDB.php');
class RecipesModel {
private $db;
public function __construct() {
$this->db = new connectDB();
}
public function delRecipe($id) {
if (is_numeric($id)) {
$sql = 'DELETE FROM t_platos WHERE ID_pl= ?';
$this->db->prepare($sql);
return $this->db->execute(array($id));
}
}
}
$recipe = new RecipesModel();
$res = $recipe->delRecipe(1);
?>
Your misunderstanding is this:
return $this->sql;
You can't return something of your choice in a constructor. The value returned by a constructor is always the object instance of that class.
Your connectDB class does not have a method called prepare().
You're probably trying to call $this->db->sql->prepare(), since in connectDB you store the actual database connection into $this->sql. However, since the $sql property is private, you can't do that.
You'll either need to make $sql a public property, or create a method in your connectDB class to act as a proxy.
There are two classes:
class Db {
public static function getConnection () {
/*Initialize parameters*/
$db = new PDO (...);
return $db;
}
}
Class Db initializes and returns a PDO object.
Then I want to do following in another class:
class User {
private $db = Db::getConnection();
....
}
Why am I getting an error here:
private $db = Db::getConnection();
Without knowing the error, it's hard to say, but I'd guess is because you can't do that there, try this.
class User {
private $db = null;
function __construct(){
$this->db = Db::getConnection();
}
public function getFriends(){
return $this->db->query('SELECT * FROM friends');
}
}
i am trying to test a function that executes a select statement, but im a bit confused about the way i should pass the connection to this function and how to assert the data.
this is the class with the function i want to test:
class AdProviders {
public $providers = null;
protected $db = null;
function __construct() {
}
function getDbh() {
if ($this->db === null){
$this->db = Slim::getInstance()->db;
}
return $this->db->getConnection();
}
function setDbh($db) {
$this->db = $db;
}
function getProviders() {
if ($this->providers == null){
$DBH = $this->getDbh();
$query = "select * from providers";
$STH = $DBH->query($query);
$STH->setFetchMode(PDO::FETCH_ASSOC);
while($provider = $STH->fetch()) {
$this->providers[$provider['id']] = $provider;
}
}
return $this->providers;
}
}
and this is my test:
require dirname(__FILE__).'/../../src/vendor/autoload.php';
class AdProvidersTest extends PHPUnit_Extensions_Database_TestCase
{
/**
* #return PHPUnit_Extensions_Database_DB_IDatabaseConnection
*/
public function getConnection()
{
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'root', 'LWw6A$cXvvf');
return $this->createDefaultDBConnection($pdo, 'testdb');
}
/**
* #return PHPUnit_Extensions_Database_DataSet_IDataSet
*/
public function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__).'/../dbTest/fixtures/providers.xml');
}
public function testgetProviders_compareResult()
{
$db = $this->getConnection();
$fixture = new AdProviders($db);
$res = $fixture->getProviders();
}
}
when i run the test function now i get the following error:
1) AdProvidersTest::testgetProviders_compareResult
Trying to get property of non-object
why am i getting it? and how can i get the data inside the providers.xml
using the getProviders? thx
You have to change the constructor of AdProviders class to that the PDO instance can be passed to it. Otherwise $fixture = new AdProviders($db); will not work.
Please change
function __construct() {
}
to
function __construct($db) {
$this->db = $db;
}
UPDATE:
I saw that you are not storing a PDO instance in your AdProviders::$db property. If your are passing a PDO instance to your __construct you should also change your method setDbh from
function getDbh() {
if ($this->db === null){
$this->db = Slim::getInstance()->db;
}
return $this->db->getConnection();
}
to
function getDbh() {
if ($this->db === null){
$this->db = Slim::getInstance()->db->getConnection();
}
return $this->db;
}
I have
class Check
{
public function __construct()
{
$this->db = new Database();
}
public function query()
{
$login = Session::get("login");
$sth = $this->db->prepare('SELECT admin FROM accounts WHERE login=:login');
$sth->execute(array(':login' => $login));
$result = $sth->fetch(PDO::FETCH_NUM);
return $result[0];
}
public static function admin()
{
echo self::query();
}
}
I have Database class in another place with PDO connection.
class Database extends PDO
{
public function __construct()
{
parent::__construct('mysql:host=localhost;dbname=name','root','pass');
$this->query('SET NAMES utf8');
}
}
So after Check::admin() code I get error:
Undefined property: View::$db
Why?
You are using a static method, that wants to use a instance variable.
Your admin method calls the query method, and the query method is using the db instance variable. As your class is not instantiated, the db variable does not exists.
My suggestion would be to make the admin method non static and use your code like this:
$mycheck = new Check();
$mycheck->admin();
or, if you are on php 5.4 and want to stick with a oneliner:
(new Check())->admin();
update
note: Do not create the db class in the constructor, but inject it:
public function __construct(Database $db)
{
$this->db = $db;
}
Sorry this is not direct answer for your question but your code has some issues so take some time and examine this and ask if it's not clear for you.
<?php
class Check {
protected $_db;
public function __construct(Database $db) {
$this->_db = $db;
}
public function query(ISession $sessionData) {
//WHY IS THE SESSION STATIC?
//$login = Session::get("login");
$sth = $this->_db->Connection()->prepare('SELECT admin FROM accounts WHERE login=:login');
$sth->execute(array(':login' => $sessionData->get("login")));
$result = $sth->fetch(PDO::FETCH_NUM);
return $result[0];
}
public function admin(ISession $sessionData) {
// REALLY BAD TO ECHO HERE
echo $this->query($sessionData);
}
}
class Database {
private $_name;
private $_password;
private $_connStr;
private $_settings;
private $_pdo;
public function __construct($connstr, $name, $password, array $settings = array()) {
$this->_name = $name;
$this->_password = $password;
$this->_connStr = $connstr;
$this->_settings = $settings;
}
public function Connection() {
if ($this->_pdo == NULL) {
$this->_pdo = new PDO($this->_connStr, $this->_name, $this->_password);
}
return $this->_pdo;
}
/* other fancy methods */
public function Close() {
$this->_pdo = NULL;
}
public function __destruct() {
$this->Close();
}
}
And i don't see why you need a Check class for all this becouse if i were you i would create somethinf like this:
$currentSession = Session::GetCurrent();
$currentSession->User()->IsInRole('admin');
Note that the session is not static and if i would write a more complete solution i would avoid Session::GetCurrent() call becouse the current session would be a field in some class' instance (HttpApplication for example).
I have a database class that I made that uses PDO to connect to my queries, I'm calling it in my main classes constructor as an object.
class MyClass
{
protected $db;
public __constructor()
{
$this->db = new Database();
}
}
class Themes extends MyClass
{
public $avatar;
public $theme_name;
public $theme_by;
public $theme_by_email;
public $theme_by_website;
public $theme_description;
public $theme_thumb;
public $theme_source;
public $theme_css;
public $theme_js;
public $theme_uploaded_on;
public function __construct()
{
parent::__construct();
$this->get_theme();
$this->get_avatar();
}
public function get_theme()
{
$sql = "SELECT *
FROM `user_themes`
WHERE `user_id` = " . $this->session->get('user_id');
if($this->db->row_count($sql))
{
$result = $this->db->fetch_row_assoc($sql);
$this->theme_name = $result['theme_name'];
$this->theme_by = $result['theme_by'];
$this->theme_by_email = $result['theme_by_email'];
$this->theme_by_website = $result['theme_by_website'];
$this->theme_description = $result['theme_description'];
$this->theme_source = $result['theme_source'];
$this->theme_css = $result['theme_css'];
$this->theme_js = $result['theme_js'];
$this->theme_uploaded_on = $result['theme_uploaded_on'];
}else{
die('no results');
}
}
}
My problem is that if I include my extended classes that calls the constructor of MyClass then I get this error:
Fatal error: Call to a member function rowCount() on a non-object in db.class.php on line 98
which points to this line in my db.class.php
class Database {
private static $PDO;
private static $config;
public function __construct() {
if (!extension_loaded('pdo'))
die('The PDO extension is required.');
self::$config = config_load('database');
self::connect();
}
...
public function row_count($statement)
{
return self::$PDO->query($statement)->rowCount(); //Line 98
}
}
If I comment out parent::__construct() from my extended classes then I'm ok and get no errors.
Try my site in FireFox, Chrom, Opera, and Safari
http://www.helixagent.com
I seem to be ok in Firefox 3.6 but all those other browsers throw me the error I mentioned...
Change your row_count-method to this:
public function row_count($statement)
{
self::$PDO->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
try {
$stmt = self::$PDO->query($statement);
$result = $stmt->rowCount();
return $result;
} catch (PDOException $e) { echo $e->getMessage(); }
return false;
}
Now you'll at least get an idea what is wrong.
Your constructor should be called __construct(), not __constructor(). So your code likely fails when calling the parent constructor.
Also, when the query()-method fails, false is returned instead of an object on which you can invoke rowcount() on. You should add a check to see if the query is successful.
This extract is from here (http://php.net/manual/en/language.oop5.basic.php)
What is the difference between $this and self ?
Inside a class definition, $this refers to the current object, while self refers to the current class.
It is necessary to refer to a class element using self, and refer to an object element using $this .
Therefore in your function row_count(...) you should use $this->PDO->query(...
[EDIT]
You could try declare $this->db = null; in your child classes before you call your parent class construct.
class MyOtherClassB extends MyClass
{
public __construct()
{
$this->db = null;
parent::__construct();
}