Extending the database class to get result from MySql - php

I have been trying to learn how to use a php class for database operations in an MVC stucture. This is a simple database class which connects to the database.
<?php
class Database
{
private $connect;
private $host, $username, $password, $databaseName;
public function __construct($host, $username, $password, $databaseName)
{
$this->host = $host;
$this->username = $username;
$this->password = $password;
$this->databaseName = $databaseName;
$this->connect = new mysqli($this->host, $this->username, $this->password, $this->databaseName);
if ($this->connect->connect_error) {
die('Connect Error (' . $this->connect->connect_errno . ') '. $this->connect->connect_error);
}
return true;
}
public function __destruct()
{
$this->connect->close();
}
}
Instantiate class for connection
$db = new Database("localhost", "root", "", "framework");
Good till here, it connects and shows and error if there is an error.
Now I have a table 'Members' in the database with three column 1. Id, 2. Name and 3. Email and to display the record in the members table
I have a Member model file in the model folder (MVC). I tried to extend the Database class like so
class Members extends Database {
public function getMembers() {
$result = $this->connect->query("SELECT * FROM members");
return $query->row;
}
}
What I am unable to do (for the past 24 hours) is display the result.
P.S. Will be great even if you can suggest me a tutorial on how to extend database class.

1). A child class cannot directly access its parent private properties, so you need public modifier method to access its properties from any of its subclasses
public function getConnect(){
return $this->connect;
}
public function getUsername(){
return $this->username;
}
public function getPassword(){
return $this->password;
}
public function getDatabaseName(){
return $this->databaseName;
}
2).Parent has a constructor to initialize these $host, $username, $password, $databaseName thus the child constructor must refer to its parent constructor in his own constructor.
In inheritance, we don't instantiate the parent class directly, but initialize its parent properties via the classes extending it (so the $host, $username, $password, $databaseName get initialized via subclasses). If you still instantiate the parent class directly, then there's no point anymore of using inheritance.
class Members extends Database {
public __construct( $host, $username, $password, $databaseName){
parent::__construct( $host, $username, $password, $databaseName);
}
public function getMembers() {
$result = $this->getConnect()->query("SELECT * FROM members");
return $query->row;
}
}

Related

Using class database connection in other class

I have a class with a connection to a database
$db = new db();
class db {
public $server = 'localhost';
public $user = '';
public $passwd = '******';
public $db = '';
public $dbCon;
function __construct() {
$this->dbCon = mysqli_connect($this->server, $this->user, $this->passwd, $this->db);
}
function __destruct() {
mysqli_close($this->dbCon);
}
}
Now i want to make an other class and using the connection like this:
class Categories (
function GetCategory($cat) {
$myQuery = "SELECT * FROM test GROUP BY $cat";
$results = mysqli_query($this->dbCon, $myQuery);
return $results;
}
)
How can i use the connection in a other class?
Can somebody help me out whit this?
Make the $dbCon in your db class a static variable, so you can access it from category's using db::$dbcon as the connection variable. You could also make a static function returning the static dbcon variable, usefull tot check if it is actually a link and not null.
This is just one solution of many possibilities, but probably the easiest to implement because it isn't likely you need more connections to a db, so a static is perfect for it.
A static is nothing more then a variable living in the namespace it is defined in, you don't need to initialize the class in order to access it. It's value is shared across all instances of the object, so creating multiple DB class instances allows you tot just return a static if it was set in a previous DB class instance.
class db{
static $link;
static function connect(){
if(self::$link = mysqli_connect(....)){
return self::$link;
} else {
die('could not connect to db');
}
}
static function getcon(){
return isset(self::$link) ? self::$link : self::connect();
}
}
class Categories{
function GetCategory($cat){
$myQuery = "SELECT * FROM test GROUP BY $cat";
return mysqli_query(db::getcon(), $myQuery);
}
}
Create an object of the db class in the categories class. Then use that object to query the db accordingly. Also make sure you use a static variable in the db class. SO that the connection variable is created once and will be used all along the application.
Your db class may look like this
class db {
public $server = 'localhost';
public $user = '';
public $passwd = '******';
public $db = '';
public static $dbCon;
function __construct() {
$this->dbCon = mysqli_connect($this->server, $this->user, $this->passwd, $this->db);
}
function __destruct() {
mysqli_close($this->dbCon);
}
}
Your categories class may look like this
class Categories {
$connection=db::$dbCon;
if(!$connection){
$db=new db();
$connection=db::$dbCon;
}
function GetCategory($cat) {
$myQuery = "SELECT * FROM test GROUP BY $cat";
$results = mysqli_query($this->connection, $myQuery);
return $results;
}
}

Call to a member function prepare() on null OOP

Having trouble understanding classes and inheritance:
core.php:
$servername = "****";
$database = "****";
$username = "****";
$password = "****";
try {
$pdo = new PDO("mysql:host=$servername;dbname=$database", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
class Database {
protected $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
}
class User extends Database {
private $ip;
private $sessionId;
public function __construct($ip, $sessionId) {
$this->ip = $ip;
$this->sessionId = $sessionId;
}
public function getSessionInfo () {
$stmt = $this->pdo->prepare(".."); <-- error here
....
}
}
When calling:
require_once 'api/core.php';
$database = new Database($pdo);
$user = new User($_SERVER['REMOTE_ADDR'], $_SESSION['info']['id']);
In this contest $database, and $user variables are not related to each other:
require_once 'api/core.php';
$database = new Database($pdo);
$user = new User($_SERVER['REMOTE_ADDR'], $_SESSION['info']['id']);
Thus, calling prepare() on $user won't work.
You need a mechanism, at least like this , although not a good practice to assign Database to a User:
$user->setDatabase($database);
Instead create a static Database object, initiate it before User initiation, and call it statically within User object, or any other object, make it available for all objects.
A quick fix would look like this, where User doesn't extend Database, because it's wrong. User is not a Database.
$database = new Database();
$user = new User();
$user->setDatabase($database); //sets $db variable inside User
//User.php
namespace MyApp;
class User{
private Database $db;
public function setDatabase($db){
$this->db = $db;
}
public function doSomething(){
$this->db->getPdo()->prepare('..');
}
}
//Database.php
namespace MyApp;
class Database{
private $pdo; //returns PDO object
function __construct(){
//create pdo connection
$this->pdo = ..
}
function getPdo(){
return $this->pdo;
}
}
Database should be injected to objects or used by objects, you shouldn't be extending Database just to have it. If you want to do it properly, in an object-oriented way.
Remember PHP doesn't allow multiple inheritances by extend. Tomorrow, you might want to have a Person class that every User will extend, but since you did it wrong in the beginning, and wasting precious extend on Database, it won't be possible. And by not having a control of how many database instances you have created, you will run into issues. You need to know for sure that you have only a single connection object for one database, if of course the opposite is a must - which in your case I doubt.
Of course this will change if you have multiple database requirements, and more sophisticated app structure.
You are receiving this error because User Instance has pdo empty. try this code
$servername = "****";
$database = "****";
$username = "****";
$password = "****";
try {
$pdo = new PDO("mysql:host=$servername;dbname=$database", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
class Database {
protected $pdo;
public function __construct($pdo) {
$this->pdo = $pdo;
}
}
class User extends Database {
private $ip;
private $sessionId;
public function __construct($pdo, $ip, $sessionId) {\
parent::__construct($pdo)
$this->ip = $ip;
$this->sessionId = $sessionId;
}
public function getSessionInfo () {
$stmt = $this->pdo->prepare("..");
....
}
}
then
require_once 'api/core.php';
$user = new User($pdo, $_SERVER['REMOTE_ADDR'], $_SESSION['info']['id']);
hope it helps.

MySQL Database connection class, function not returning any results

I am currently working on a small project and, for the love of god, I cannot get this PHP class working.
The problem is, doQuery doesn't return anything nor modifies the DB when I type and INSERT or any other command here, always returns false even when called from within the class.
class CONN {
private $connection;
public function __construct() {
$this->connection = new mysqli($address, $user, $pass, $db);
if ($this->connection->connect_error) {
// Throw error here
} else {
$this->doQuery("SET NAMES 'utf8'");
}
}
public function doQuery($query){
return $this->connection->query($this->connection->real_escape_string($query));
}
}
Solved
The real_escape_string escaped even ' and hence the query could not work.
I don't think your code will ever work like that, the main issue i see is the following piece of code:
$this->connection = new mysqli($address, $user, $pass, $db);
Where do $adress, $user, $pass, $db come from? Maybe you missed your constructor arguments.
Use real_escape_string only for escaping variables (usually submitted by users) e.g.
$this->doQuery("SELECT * FROM table WHERE something='".$this->connection->real_escape_string($_POST['data'])."'"
do not escape whole query
public function doQuery($query){
return $this->connection->query($query);
}
You need to create/provide additional class arguments. When object is created class consructor needs those values to make a connection. So:
class Con
{
private $address;
private $username;
private $password;
private $database;
public function __construct($address, $username, $password,$database)
{
$this->address = $address;
$this->username = $username;
$this->password = $password;
$this->database = $database;
}
public function connect()
{
$con = mysqli_connect($this->address, $this->username, $this->password, $this->database);
return $con;
}
}
$conobject = new Con("localhost","root","","mybase");
$convar = $conobject->connect();

PHP OOP and PDO

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.

Extending the MySQLi class

I want to be able to make classes which extend the MySQLi class to perform all its SQL queries.
$mysql = new mysqli('localhost', 'root', 'password', 'database') or die('error connecting to the database');
I dont know how to do this without globalising the $mysql object to use in my other methods or classes.
class Blog {
public function comment() {
global $mysql;
//rest here
}
}
Any help would be appreciated.
Thanks.
I was working on something similar. I'm happy about this singleton class that encapsulates the database login.
<?php
class db extends mysqli
{
protected static $instance;
protected static $options = array();
private function __construct() {
$o = self::$options;
// turn of error reporting
mysqli_report(MYSQLI_REPORT_OFF);
// connect to database
#parent::__construct(isset($o['host']) ? $o['host'] : 'localhost',
isset($o['user']) ? $o['user'] : 'root',
isset($o['pass']) ? $o['pass'] : '',
isset($o['dbname']) ? $o['dbname'] : 'world',
isset($o['port']) ? $o['port'] : 3306,
isset($o['sock']) ? $o['sock'] : false );
// check if a connection established
if( mysqli_connect_errno() ) {
throw new exception(mysqli_connect_error(), mysqli_connect_errno());
}
}
public static function getInstance() {
if( !self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
public static function setOptions( array $opt ) {
self::$options = array_merge(self::$options, $opt);
}
public function query($query) {
if( !$this->real_query($query) ) {
throw new exception( $this->error, $this->errno );
}
$result = new mysqli_result($this);
return $result;
}
public function prepare($query) {
$stmt = new mysqli_stmt($this, $query);
return $stmt;
}
}
To use you can have something like this:
<?php
require "db.class.php";
$sql = db::getInstance();
$result = $sql->query("select * from city");
/* Fetch the results of the query */
while( $row = $result->fetch_assoc() ){
printf("%s (%s)\n", $row['Name'], $row['Population']);
}
?>
My suggestion is to create a Singleton DataAccess class, instantiate that class in a global config file and call it in your Blog class like $query = DataAccess::query("SELECT * FROM blog WHERE id = ".$id).
Look into the Singleton pattern, it's a pretty easy to understand designpattern. Perfect for this situation.
Your DataAccess class can have several methods like query, fetchAssoc, numRows, checkUniqueValue, transactionStart, transactionCommit, transactionRollback etc etc. Those function could also be setup as an Interface which gets implemented by the DataAccess class. That way you can easily extend your DataAccess class for multiple database management systems.
The above pretty much describes my DataAccess model.
You can use PHP's extends keyword just for any other class:
class MyCustomSql extends mysqli {
public function __construct($host, $user, $password, $database) {
parent::__construct($host, $user, $password, $database);
}
public function someOtherMethod() {
}
}
$sql = new MyCustomSql('localhost', 'root', 'password', 'database') or die('Cannot connect!');
or better use object aggregation instead of inheritance:
class MySqlManipulator {
private $db;
public function __construct($host, $user, $password, $database) {
$this->db = new mysqli($host, $user, $password, $database);
}
public function someOtherMethod() {
return $this->db->query("SELECT * FROM blah_blah");
}
}
$mysqlmanipulator = new MySqlManipulator('localhost', 'root', 'password', 'database') or die('Cannot connect!');
My standard method is to make a singleton class that acts as the database accessor, and a base class that everything requiring such access inherits from.
So:
class Base {
protected $db;
function __construct(){
$this->db= MyDBSingleton::get_link();
//any other "global" vars you might want
}
}
class myClass extends Base {
function __construct($var) {
parent::__construct();// runs Base constructor
$this->init($var);
}
function init($id) {
$id=(int) $id;
$this->db->query("SELECT * FROM mytable WHERE id=$id");
//etc.
}
}
Have a look at PDO, which throw exceptions for you to catch if a query fails. It's widely used and tested so you shouldn't have a problem finding existing solutions whilst using it.
To inject it into your blog class:
class Blog {
private $_db;
public function __construct(PDO $db) {
$this->_db = $db
}
public function comment() {
return $this->_db->query(/*something*/);
}
}

Categories