I'm refactoring my PHP code, so that the insertion of data into my database is kept separate from the class that creates the database connection. I'm trying to implement the Single Responsibility Principle, but transferring my code (for inserting data) to a separate class results in the PDO::prepare statement becoming an 'undefined method'.
I have tried to instantiate my database class ('DB.php') and pass the object to the class that inserts data ('Register.php').
The DB class:
<?php
class DB
{
public $dbServer,
$dbUsername,
$dbPassword,
$dbName,
$pdo,
$stmt;
function __construct($dbServer,
$dbUsername,
$dbPassword,
$dbName)
{
$this->dbServer = $dbServer;
$this->dbUsername = $dbUsername;
$this->dbPassword = $dbPassword;
$this->dbName = $dbName;
$this->connect();
}
public function connect()
{
try {
$this->pdo = new PDO("mysql:host=" . $this->dbServer .
"; dbname=" . $this->dbName,
$this->dbUsername,
$this->dbPassword);
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
exit("Could not connect to database: " . $e->getMessage() );
}
}
}
The Register class:
<?php
class Register
{
public $pdo,
$dbh,
$stmt,
$conn;
function __construct(DB $pdo)
{
$this->pdo = $pdo;
// $this->conn = $this->pdo->connect();
}
public function register(Validate $val)
{
try {
$this->stmt = $this->pdo->prepare(
"INSERT INTO registration(firstName,
surname,
email,
username,
password,
gender,
area)
VALUES(:firstName,
:surname,
:email,
:username,
:password,
:gender,
:area)");
$this->stmt->bindParam(':firstName', $val->firstName);
$this->stmt->bindParam(':surname', $val->surname);
$this->stmt->bindParam(':email', $val->email);
$this->stmt->bindParam(':username', $val->username);
$this->stmt->bindParam(':password', $val->password);
$this->stmt->bindParam(':gender', $val->gender);
$this->stmt->bindParam(':area', $val->area);
$this->stmt->execute();
} catch(PDOException $e) {
echo 'Error: ' . $e->getMessage();
}
}
}
My Configuration file:
<?php
$dbServer = '127.0.0.1';
$dbUsername = 'root';
$dbPassword = '';
$dbName = 'assignment';
spl_autoload_register(function($class)
{
require 'classes/' . $class . '.php';
} );
$db = new DB($dbServer, $dbUsername, $dbPassword, $dbName);
$database = new Register($db);
The actual Registration page:
<?php
require('core/config.php');
if( isset($_POST['submit']) ) {
$firstName = $_POST['firstName'];
$surname = $_POST['surname'];
$email = $_POST['email'];
$username = $_POST['username'];
$password = $_POST['password'];
$gender = $_POST['gender'];
$area = $_POST['area'];
$val = new Validate($firstName, $surname, $email, $username, $password, $gender, $area);
$val->filter();
$database->register($val);
}
?>
This implementation results in the following notice:
Fatal error: Uncaught Error: Call to undefined method DB::prepare()
Why doesn't the PDO class communicate its in-built prepare() function to my Register class? I have viewed 'Fatal error: Call to undefined method Database::prepare()' on Stack Overflow and sought to remedy my code:
$this->conn = $this->pdo->connect();
(See the commented statement in my Register class.) However, $this->conn ends up returning a NULL instead of my database connection.
Related
UPDATE: There was no issue with the code used in counting. There was just a typo error in connecting to database
$this->conn = new PDO("mysql:host=". $this->host . ";db_name=" . $this->db_name, $this->username, $this->password);
the db_name should be dbname. So its something like
$this->conn = new PDO("mysql:host=". $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
I am try a PHP REST api with mysql database but this doesn't seem to be working as i have tried to select from my database as the first step but this returns no result despite there being a record in the database
Below are my codes
database.php
<?php
class Database
{
//Database Credentials
private $host = "localhost";
private $username = "root";
private $password = "password";
private $db_name = "rtmdb";
public $conn;
//Get Database Connection
public function getConnection()
{
$this->conn = null;
//Try connection
try
{
$this->conn = new PDO("mysql:host=". $this->host . ";db_name=" . $this->db_name, $this->username, $this->password);
$this->conn->exec("set names utf8");
}
catch(PDOException $exception)
{
echo "Connection error:" . $exception->getMessage();
}
return $this->conn;
}
}
admin.php to select from database
<?php
class Admin
{
//Database Connection and Table name
private $conn;
private $table_name = "admin";
//object properties
public $id;
public $fname;
public $lname;
public $oname;
public $uname;
public $email;
public $idnumber;
public $password;
public $profimage;
public $datecreated;
public $modifiedby;
public $datemodified;
public $status;
//Construct $db as database connection
public function __construct($db)
{
$this->conn = $db;
}
public function crawl()
{
$query = "SELECT * FROM " . $this->table_name;
$stmt = $this->conn->prepare($query);
$stmt->execute();
return $stmt;
}
}
crawl.php file to get data and json_encode results
//Include database and object files
include_once "../config/database.php";
include_once "../objects/admin.php";
$database = new Database();
$db = $database->getConnection();
$admin = new Admin($db);
//Query Admin
$stmt = $admin->crawl();
$num = $stmt->rowCount();
echo json_encode($num);
if($num > 0)
{
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
{
extract($row);
$admin_list = array(
"id" => $id,
"uname" => $uname
);
array_push($admin_arr['records'], $admin_list);
}
echo json_encode($admin_arr);
}
else
{
echo json_encode(
array("message" => "No registered admin found.")
);
}
But i get rowCount() as 0 and "no registered admin" despite having records
Below are screenshots of my table structures
the database structure
I also have only one data in the database
But these seem to give me no result. Please what the issue and how do i fix?
I know must coding part of mysql bt new at mysqli. I am not able to execute these insert query to the database. I have searched a lot but couldn't find simple suggestion, or may be i didn't understand.
Undefined variable: mysqli in C:\wamp\www\New folder\php\msqliconnect.php on line 32
Fatal error: Call to a member function mysqli_query() on a non-object in C:\wamp\www\New folder\php\msqliconnect.php on line 32
Any help is appreciated.
<?php
class connection
{
public $mysqli;
function connect()
{
$hostname = "localhost";
$username = "root";
$password = "";
$database = "demodatabase";
$mysqli = new mysqli($hostname, $username, $password, $database);
/* check connection */
if (mysqli_connect_errno())
{
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
return true;
}
}
class Index extends connection
{
function __construct()
{
parent::connect();
}
function insertdata($a, $b)
{
// echo $a. ' ' .$b;
// MySqli Insert Query
$status = 0;
$insert_row = $mysqli->mysqli_query("INSERT INTO tb_user (id, user, password, status) VALUES('','" . $a . "', '" . $b . "', '')");
if ($insert_row)
{
print 'saved';
}
else
{
die('Error : (' . $mysqli->errno . ') ' . $mysqli->error);
}
}
}
?>
In both of your connect() and insertdata() methods, you're using local variable $mysqli, not the instance variable public $mysqli;. You should use $this->mysqli instead of $mysqli in your instance methods. So your connect() and insertdata() methods would be like this:
function connect(){
$hostname = "localhost";
$username = "root";
$password = "";
$database = "demodatabase";
$this->mysqli = new mysqli($hostname, $username, $password, $database);
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
return true;
}
and
function insertdata($a, $b){
$insert_row = $this->mysqli->query("INSERT INTO tb_user (id, user, password, status) VALUES('','".$a."', '".$b."', '')");
if($insert_row){
print 'saved';
}else{
die('Error : ('. $this->mysqli->errno .') '. $this->mysqli->error);
}
}
Sidenote: Learn about prepared statement because right now your query is susceptible to SQL injection attack. Also see how you can prevent SQL injection in PHP.
This question already has answers here:
pdo - Call to a member function prepare() on a non-object [duplicate]
(8 answers)
Closed 6 years ago.
i am getting error : Fatal error: Using $this when not in object context in line $stmt_edit = $this->conn->prepare('SELECT userName, userEmail, phone FROM tbl_users WHERE userID =:uid'); , i followed this , this
& this and all other google , yahoo links but nothing worked for me, please check below code and help me.
usr
global $DB_con;
error_reporting( ~E_NOTICE );
require_once 'dbconfig.php';
if(isset($_GET['edit_id']) && !empty($_GET['edit_id']))
{
$id = $_GET['edit_id'];
$stmt_edit = $this->conn->prepare('SELECT userName, userEmail, phone FROM tbl_users WHERE userID =:uid');
$stmt_edit->execute(array(':uid'=>$id));
$edit_row = $stmt_edit->fetch(PDO::FETCH_ASSOC);
extract($edit_row);
}
else
{
header("Location: home.php");
}
dbconfig
<?php
$db = isset($_POST['db']) ? $_POST['db'] : '';
class Database
{
private $host = "localhost";
private $db_name = "designer3";
private $username = "root";
private $password = "123456";
public $conn;
public function dbConnection()
{
global $DB_con;
$db = isset($_POST['db']) ? $_POST['db'] : '';
$this->conn = null;
try
{
$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $exception)
{
echo "Connection error: " . $exception->getMessage();
}
return $this->conn;
}
}
?>
update
i tried by creating new object un user page, but still it did't worked for me : gave this strange error : Fatal error: Call to a member function prepa‌​re() on a non-object in
code
$oDb=new Database();
$custDb=$oDb->dbConnection();
$custDb->conn->prepare('SELECT userName, userEmail, phone FROM tbl_users WHERE userID =:uid');
Your code should be
global $DB_con;
error_reporting( ~E_NOTICE );
require_once 'dbconfig.php';
if(isset($_GET['edit_id']) && !empty($_GET['edit_id']))
{
$id = $_GET['edit_id'];
$stmt_edit = $DB_con->conn->prepare('SELECT userName, userEmail, phone FROM tbl_users WHERE userID =:uid');
$stmt_edit->execute(array(':uid'=>$id));
$edit_row = $stmt_edit->fetch(PDO::FETCH_ASSOC);
extract($edit_row);
}
else
{
header("Location: home.php");
}
$this reference to the current object, it's most commonly used in object oriented code.
Reference: http://www.php.net/manual/en/language.oop5.basic.php
Primer: http://www.phpro.org/tutorials/Object-Oriented-Programming-with-PHP.html
and your dbconfig.php should be
<?php
$db = isset($_POST['db']) ? $_POST['db'] : '';
class Database
{
private $host = "localhost";
private $db_name = "designer3";
private $username = "root";
private $password = "123456";
public $conn;
public function dbConnection()
{
global $DB_con;
$db = isset($_POST['db']) ? $_POST['db'] : '';
$this->conn = null;
try
{
$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $exception)
{
echo "Connection error: " . $exception->getMessage();
}
$DB_con=$this->conn;
return $this->conn;
}
}
?>
I am a beginner in OOP in PHP and I am trying to play with my code. So first thing I wanted to do is to write one basic class with connect and insert functions for database. So my desired situation is this:
-I wanna create on class which will controll connect and insert functions. The problem is, my $connect variable isn't working from another function, so what could I do to make that possible?
You will understand more by the code provided.
<?php
class DB {
protected $dbhost = 'localhost';
protected $dbuser = 'root';
protected $dbpass = '';
protected $dbname = 'newdb';
public function connect()
{
$connect = new mysqli($this->dbhost, $this->dbuser, $this->dbpass, $this->dbname);
if($connect->error)
{
echo "Failed to connect";
}
else
{
echo "connected";
}
}
public function insert($name, $second)
{
$insert = "INSERT INTO posts (name, second) VALUES ('$name', '$second')";
if ($connect->query($insert) === TRUE)
{
echo "New record created successfully";
}
else
{
echo "Error: " . $sql . "<br>" . mysqli_connect_error();
}
}
}
require_once 'classes/DB.php';
$db = new DB;
if(isset($_POST['submit']))
{
$name = $_POST['name'];
$second = $_POST['second'];
$db->insert($name, $second);
}
?>
<form method="POST">
Add smth<input type="text" name="name"><br>
Also omg<input type="text" name="second"><br>
<input type="submit" name="submit">
</form>
Add $connect as a property of your class, so you may reuse it everywhere within the class using $this->connect:
class DB
{
protected $dbhost = 'localhost';
protected $dbuser = 'root';
protected $dbpass = '';
protected $dbname = 'newdb';
protected $connect;
public function connect()
{
$this->connect = new mysqli($this->dbhost, $this->dbuser, $this->dbpass, $this->dbname);
if ($this->connect->error)
{
echo "Failed to connect";
}
else
{
echo "connected";
}
}
public function insert($name, $second)
{
$insert = "INSERT INTO posts (name, second) VALUES ('$name', '$second')";
if ($this->connect->query($insert) === TRUE)
{
echo "New record created successfully";
}
else
{
echo "Error: " . $sql . "<br>" . mysqli_connect_error();
}
}
}
I have rewritten your class for a bit, so you can insert your database settings in the constructor. So it really is a object, and you can use multiple databases. What you did wrong in your class was using the variable $connect without declaring it into a variable usable in the whole class.
The class
<?php
class DB {
protected $dbhost;
protected $dbuser;
protected $dbpass;
protected $dbname;
protected $connection;
public function __construct($dbhost, $dbuser, $dbpass, $dbname)
{
$this->dbhost = $dbhost;
$this->dbuser = $dbuser;
$this->dbpass = $dbpass;
$this->dbname = $dbname;
$connection = new mysqli($this->dbhost, $this->dbuser, $this->dbpass, $this->dbname);
if($connection->error)
die('Could not connect with the database!');
$this->connection = $connection;
}
public function connect()
{
$this->__construct($this->dbhost, $this->dbuser, $this->dbpass, $this->dbname);
}
public function insert($name, $second)
{
$insert = "INSERT INTO posts (name, second) VALUES ('$name', '$second')";
if ($this->connection->query($insert) === TRUE)
{
echo "New record created successfully";
}
else
{
echo "Error: " . $sql . "<br>" . mysqli_connect_error();
}
}
public function getConnection()
{
return $this->connection;
}
}
Usage
$db = new DB('localhost', 'root', '', 'newdb');
$db->insert('name', 'second');
I hope this helps you in your journal through OOP, sorry for my bad English.
The parts in bold are what I am questioning. Inside the search_for_new_user function, if I change $conn->prepare to $this->db_connection()->prepare. I receive a lost connection error. However in the function right above it db_conn_test I can use this syntax. In both cases I am returning the $connection so I don't understand why there must be a difference in syntax.
class Database {
function db_connection() {
$server = "localhost";
$user = "user";
$password = "password";
$database = "database";
return $connection = new mysqli($server, $user, $password, $database);
}
function db_conn_test() {
if (**$this->db_connection()->connect_errno**) {
die($this->db_connection()->connect_errno . ": " . $this->db_connection()->connect_error);
} else {
echo "connected to mysql database";
}
}
function search_for_new_user($email) {
**$conn = $this->db_connection();**
if ($stmt = **$conn->prepare**("SELECT email FROM users where email = ?")) {
$stmt->bind_param("s", $email);
$stmt->execute();
$stmt->bind_result($result);
$stmt->fetch();
echo $result;
$stmt->close();
$conn->close();
}
}
}
In db_conn_test you call db_connection twice only if you got connection error during first db_connection call, so in this case connection to DB is not created.
But in search_for_new_user you create connection twice.
I.e.:
in db_conn_test:
// if connection not created, because you got error
if ($this->db_connection()->connect_errno) {
// therefore each time you call db_connection(),
// you again try create connection, and got same error
// and return it in die text
die($this->db_connection()->connect_errno . ": " . $this->db_connection()->connect_error);
} else {
echo "connected to mysql database";
}
but in search_for_new_user: you call db_connection() and create connection(if all is ok). And then if you call db_connection in second try, first connection is gone away and you got error.
Your class should looks like this:
class Database {
protected $connection;
function db_connection() {
if ($this->connection !== null) {
return $this->connection;
}
$server = "localhost";
$user = "user";
$password = "password";
$database = "database";
return $this->connection = new mysqli($server, $user, $password, $database);
}
}