require("classes/controller.class.php");
$db = new mysqli(__DBHOST, __DBUSER, __DBPASS, __DBDATA);
if ($db->connect_errno) {
printf("Connect failed: %s\n", $db->connect_error);
exit();
}
$controller = new Controller;
Within the Controller class I want to use the $db MySQLi connection. So within a public function I used:
$result = $db->query("SELECT * FROM colors");
var_dump($result);
But I get this error:
Fatal error: Call to a member function query() on a non-object in /home/cloud/public/teamdresser/controllers/IndexController.php on line 8
Am I doing something wrong? Do I need to pass the $db connect first, or use global or something?
Thanks in advance
If $db is a global variable, you'll need to import it in your function:
public function YourFunction()
{
global $db;
$result = $db->query("SELECT * FROM colors");
..
}
Instead of doing this, you might want to consider encapsulating $db in a database class and create it as a singleton, or, arguably better, pass it to the constructor of Controller. But that remark might lead to new discussions about design, while complete books have been written about this subject. So for now, just import the global like described above. ;)
You could use a class with a singleton instance
class Database {
private static $_instance;
public static function getInstance() {
//If the connection is not initialized, this creates it and store
if (empty(Database::$_instance))
Database::$_instance = new Database();
return Database::$_instance;
}
private $_db;
private function __construct() {
$this->_db = new mysqli(__DBHOST, __DBUSER, __DBPASS, __DBDATA);
if ($db->connect_errno) {
printf("Connect failed: %s\n", $db->connect_error);
exit();
}
}
private function __destruct() {
$this->_db->close();
}
public function query($query) {
return $this->_db->query($query);
}
}
You called in this manner
$result = Database::getInstance()->query("SELECT * FROM colors");
You have created a connection and executed with calling a function. Once the script is terminated, the connection will be autorealeased by the destructor.
This should be only a start point. You could create all functionality that you want (e.g. escape parameters, insert, update, delete, and so on...)
Related
Ok,
This is sort of an involved problem, but any help or advice would be incredibly appreciated.
So I'm working with a site that (using .htaccess) redirects all traffic to a load.php. For any sql functionality, I have an abstract class that has a lot of query statements as functions that pass parameters to define the specifics of each query.
e.g.
$table->update("constraints")
I'm trying to figure out how to set the connection to the database on load.php, and then set the connection as a variable ($mysqli) that can then be referenced in my abstract query class without having to pass the parameter to every single query function call.
Again, any help or advice would be appreciated.
Here's an example of a function:
function clearTable (){
$mysqli = dbConnect::connect();
$sql = "TRUNCATE TABLE $this->tablename";
$mysqli->query($sql);
}
If I connect to the database in a construct function and set $this->mysqli and replace $mysqli = dbConnect::connect(); with $mysqli = $this->mysqli, none of the queries work. Though they work with a fresh reconnect on each call.
You should use Dependency Injection for this.
Basically it means that the class that needs the database connection doesn't create the connection, it just receives the already instasiated instance.
Example
In some init file:
// Create the db connection
$db = new Mysqli(......);
// Pass it to the query class that needs it
$queryClass = new QueryClass($db);
Then in your class file:
class QueryClass
{
protected $db;
public function __construct($db)
{
// $this->db will now be the same Mysql instance
$this->db = $db;
}
public function doSomeQuery()
{
$this->db->query(....);
}
}
A bonus for this is that you don't need to touch the QueryClass, if you ever want to start making some unit tests. You only need to pass a DB connection to a test database instead.
After looking through this a bit more, I can also create my db::connect() function to look like this:
class dbConnect {
private static $db;
private $mysqli;
private function __construct() {
$this->mysqli = new mysqli(HOST, USER, PASSWORD, DATABASE);
}
function __destruct() {
$this->mysqli->close();
}
public static function connect() {
if (self::$db == null) {
self::$db = new dbConnect();
}
return self::$db->mysqli;
}
}
and pass that as $this->mysqli in the query functions file
recently I came across Mockery Framework for PHP mock object. I have a class which has constructor which takes postgreSQL connection parameters and connects to database and other methods for DML operations. I want to write test cases for these methods without actual connecting to database, hence want to use Mockery.
Below is a simple example of DBConnection class. Could any one please give me a sample code for running test case for select method?
class DBConnection {
private $conn; //db connection
private $debug = false;
private $schema;
public function __construct($host, $user, $pass, $db, $schema = 'main', $debug = DEBUG) {
$this->debug = $debug;
$this->conn = pg_connect("host=$host user=$user password=$pass dbname=$db");
if(!$this->conn) {
throw new DatabaseException('Database connection failed');
}
}
public function select() {
$result = pg_prepare($this->conn, "my_query", 'SELECT * FROM shops WHERE name = $1');
$result = pg_execute($this->conn, "my_query", array("Joe's Widgets"));
return $result;
}
}
I'm assuming you want to mock the DBConnection->select() method and ensure that the pg_prepare() and pg_execute() functions are called.
If the above is true, I wrote a composer package to help try to test php function calls unit-testing/function-spy (https://github.com/unit-testing/function-spy)
First, you'll have to namespace your DBConnection class. Let's assume it's in namespace MyNamespace. Then in your test, you can do something like this:
<?php namespace MyNamespace
use UnitTesting\FunctionSpy\Spy;
class DBConnectionTest extends \PHPUnit_Framework_TestCase {
use \UnitTesting\FunctionSpy\SpyTrait;
protected function setUp()
{
// init the spy
$this->initSpy();
}
protected function tearDown()
{
// flush the spy so we can reset the calls after every test
$this->flushSpy();
}
function test_construct_callsPgConnect_AndSetsConnection()
{
// create a fake return value for pg_connect()
$this->spy['pg_connect'] = 'connection';
$object = new DBConnection('host', 'user', 'pass', 'db', 'schema');
$this->assertFunctionLastCalledWith('pg_connect', array('host=host user=user password=pass dbname=db'));
$conn = $object->getConnection(); // your class doesn't have this method implemented, but it just returns the connection
$this->assertEquals('connection', $conn);
}
}
function pg_connect()
{
return Spy::pg_connect();
}
I'm very new to oop in php, so far i'm using multiple classes that I made in one php file, such as:
class Style {
//stuff
}
class User {
//other stuff
}
And many more, yet i'm having an issue on how to connect to mysql within these classes, if I use $db = new Mysqli(); how will I be able to make queries from inside classes? what if i'm trying to make my own connector class like so:
class Connection extends mysqli {
public function __construct($host, $user, $pass, $db) {
parent::__construct($host, $user, $pass, $db);
if (mysqli_connect_error()) {
die('Connect Error (' . mysqli_connect_errno() . ') '
. mysqli_connect_error());
}
}
}
How can I be able to make queries from within different classes? Or what's a better way of using oop in php correctly? with multiple classes to organize different parts of code?
Any help or tips will be appreciated, thanks. What about using PDO? does that make everything easier?
class Style {
public function __construct($conn) {
$this->conn = $conn;
//use $this->conn in the class
}
}
$db = new Mysqli();
$style = new Style($db);
I think the first example is the preferred method, however you could create a simple registry class and use that to store a $db object etc.
If possible I would probably use PDO but that doesn't solve this issue.
Since you are extending the mysqli class you will have access to the functions as you would if you instantiated that class by itself (so long as those functions aren't private). Some folks though (including myself) will instantiate the DB connection in their own custom class with a database connection, then inject that class into classes that need it.
class MyDatabase {
private $this->dbi;
public function __construct() {}
public function connectDB($host, $user, $pass, $db)) {
//You can do this in the constructor too, doesn't have to be its own function
$this->dbi = new mysqli($host, $user, $pass, $db);
}
public function getDBI() {
return $this->dbi;
}
}
You can add all the functions you want to your own class (or an extended class), you can also have any class that needs a database extend your DB class. But that isn't really preferred (each class will have a different db class/connection). The easiest is probably to import your DB connection into your class. Either through the constructor or another function;
class MyClass {
private $this->database;
public function __construct($db) {
$this->database = $db->getDBI();
}
public function query($q) {
//Of course, clean your data first, and best practices use prepared statements
$result = $this->database->query($q);
return $result;
}
}
Then make your database connection and inject it into your class.
$db = new MyDatabase();
$db->connectDB('localhost', 'username', 'password', 'mydb');
$class = new MyClass($db);
$resultSet = $class->query("SELECT * FROM MyTable"); //Obviously anything the user could add here is to not be trusted.
using PDO will give you a lot of functions and flexebilty and it has many drivers built-in.
to make what you are trying to do here is a sample :
STEP 1 :
Make a Main class that will handle your database :
class app extends PDO {
protected $database_hostname = "localhost";
protected $database_username = "root";
protected $database_password = "";
protected $database_name = "testdb";
protected $database_type = "mysqli";
public function __construct() {
try {
parent::__construct($this->database_type . ':host=' . $this->database_hostname . ';dbname=' . $this->database_name, $this->database_username, $this->database_password, array(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION));
} catch (PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
}
}
STEP 2 :
then you need to initilze a globale variable as your Database :
$db= new app() ;
STEP 3 :
include a local variable to handle database in the other classes :
class User{
public $db ;
}
STEP 4 :
in the constructor of the other classes ( user for exemple ) you need to pass the local variable by reference to the globale variable :
class User{
public $db ;
public function __construct(){
global $db;
$this->db =& $db;
}
}
STEP 5 :
then if you want to execute a request from inside a class you do it by the local variable :
$this->db->query("SELECT * FROM user");
and from the outside just by using : $db->query("SELECT * FROM user");
I hope that helped !
I'm trying to create a simple class based on my database PDO class that I can say "get this id" and it will print the info. I'm trying to do this in "qu" but get the following error: "Call to undefined method qu::get()".
There's probably a mixture of problems so any help here would be awesome. Thanks a lot!!
class db {
protected static $conn;
private function __construct(){}
public static function connect() {
if (!isset(self::$conn)) {
self::$conn = new PDO('mysql:host=localhost;dbname=database', DB_USER, DB_PASSWORD);
}
return self::$conn;
}
}
class qu {
private $db;
function quconn (&$db){
$this->db = &$db;
}
private static function getq($id){
$sql="SELECT * FROM table WHERE id=:id";
$stmt = self::quconn()->prepare($sql);
$stmt->execute(array(':id'=> $id));
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $result;
}
}
//$data = db::connect()->query("SELECT * FROM table")->fetchAll(); // this works
$data = qu::getq("22"); //can i use something like this? this causes the error
print_r($data);
function getq of class qu should be marked with public access modifier.
Otherwise the following row will fail as getq is a private function
$data = qu::getq("22");
Second and issue in this code
function quconn (&$db){
$this->db = &$db;
}
As you enter function quconn from a static content $this is unavailable.
Use self::$db instead.
For class qu follow the same structure of class db wich is a singleton mnagament class.
I also suggest to clarify yourself differences between $this and self, static contest etc..
Php offiacial documentation offers al lot about
Also i don't think you need passing-by-reference method:
try to rewrite the quconn function as follows:
function quconn ($db){
self::$db = $db;
}
By the way i don't thing the class qu is well "engineered"
Even if you correct the passing-by-reference-problem this instruction won't work:
$stmt = self::quconn()->prepare($sql);
You are invoking the prepare function on the result of the invocation to quconn, which doesn't return anything...
I suggest:
$stmt = db::connect()->prepare($sql);
this get the PDP instance and call the prapare method....
I am trying to convert code from mysql to mysqli.
The code uses a single mysql_connect in a file which is included by every other file.
mysql_connect returns a MySQL link identifier that is a superglobal so you can rely on having a database connection available in any of your own functions.
It looks like with mysqli_connect this is not the case, the object returned isn't global.
Does this mean I have to add : global $mysqli; at the top of every function, or is there an way of making it a superglobal?
Relying on the fact that PHP will use the last opened connection resource if you don't specify one, is probably not a very good idea.
What happens if your application changes and you need two connections, or the connection is not there?
So it seems you need to do some refactoring anyway.
Here's a solution similar to Karsten's that always returns the same mysqli object.
class DB {
private static $mysqli;
private function __construct(){} //no instantiation
static function cxn() {
if( !self::$mysqli ) {
self::$mysqli = new mysqli(...);
}
return self::$mysqli;
}
}
//use
DB::cxn()->prepare(....
I usually make a function:
$mysqli = new mysqli(...);
function prepare($query) {
global $mysqli;
$stmt = $msqyli->prepare($query);
if ($mysqli->error()) {
// do something
}
return $stmt;
}
function doStuff() {
$stmt = prepare("SELECT id, name, description FROM blah");
// and so on
}
and then call that. That being said, I've since abandoned mysqli as being too bug-ridden to be considered usable. Shame really.
A very simple way to do this would be with a fixed database class, just to hold the mysqli connection object:
class Database {
public static $connection;
}
Database::$connection = new mysqli(HOST, USERNAME, PASSWORD, DATABASE);
Then you can access it in the normal ways:
$sql = 'SELECT * FROM table';
$result = Database::$connection->query($sql);
$result = mysqli_query(Database::$connection, $sql);
echo 'Server info ' . mysqli_get_server_info(Database::$connection);
To introduce some oop to you and solve your problem, you could use a class like this:
class MyDatabase
{
private static $_connection;
public static function connect()
{
$mysqli = new mysqli(...);
self::$_connection = $mysqli;
}
public static function getConnection()
{
return self::$_connection;
}
}
In your database-connection file you would load this class and execute MyDatabase::connect(); once.
To get the $mysqli-connection anywhere in your script, just call MyDatabase::getConnection();.