I've made a simple Database class to handle my database connections. But it's somehow not working? At first it wasn't working with MySQLi, so i tried PDO – which ain't working either.
I am however eager to make PDO work. I've already googled and searched here at StackOverflow, but without luck.
Here's my class:
class Database
{
// Local
protected $_host = "localhost";
protected $_user = "root";
protected $_pass = "root";
protected $_database = "hs";
protected $_connection;
// Construct
private function __construct()
{
try
{
$this->_connection = new PDO('mysql:host=localhost;dbname=hs', $this->_user, $this->_pass);
$this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo 'ERROR: ' . $e->getMessage();
}
}
public function login($usr, $pwd)
{
echo "hi";
}
}
And here's the execution:
if(isset($_POST['hs_login']))
{
$db = new Database;
$db->login($_POST['hs_username'], $_POST['hs_password']);
}
Thanks in advance! :)
Constructors are always public so change that like so:
class Database
{
// Local
protected $_host = "localhost";
protected $_user = "root";
protected $_pass = "root";
protected $_database = "hs";
protected $_connection;
// Construct
public function __construct()
{
try
{
$this->_connection = new PDO('mysql:host=localhost;dbname=hs', $this->_user, $this->_pass);
$this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e)
{
echo 'ERROR: ' . $e->getMessage();
}
}
public function login($usr, $pwd)
{
echo "hi";
}
}
Also, new Database is a method call so change that like so:
if(isset($_POST['hs_login']))
{
$db = new Database;
$db->login($_POST['hs_username'], $_POST['hs_password']);
}
Just wanted to point out, that there are some cases, when you can use private constructors. One of the practical use of them is with Databases, so it's relevant in your case as well. This design pattern is called Singleton pattern, and it relies on static method calls. You don't have to instantiate the class, as instantiation is handled by the class itself. I've put together an example:
<?php
class Database {
private static $instance = null;
private $db;
private static $last_result;
private function __construct() {
try {
$pdo_param = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
$this->db = new PDO("mysql:host=YOUR_HOSTNAME;dbname=YOUR_DBNAME", "YOUR_USERNAME", "YOUR_PASSWORD", $pdo_param);
}
catch (PDOException $e) {
die($e->getMessage());
}
}
private static function getInstance() {
if (self::$instance == null) {
self::$instance = new self();
}
return self::$instance;
}
public static function query($sql) {
try {
$instance = self::getInstance();
$stmt = $instance->db->prepare($sql);
$stmt->execute();
self::$last_result = $stmt->fetchAll();
return self::$last_result;
}
catch (PDOException $e) {
die($e->getMessage());
}
}
public static function prepare($sql, $params) {
try {
$instance = self::getInstance();
$stmt = $instance->db->prepare($sql);
$stmt->execute($params);
self::$last_result = $stmt->fetchAll();
return self::$last_result;
}
catch (PDOException $e) {
die($e->getMessage());
}
}
}
$users = Database::query("SELECT * FROM users");
$filtered_users = Database::prepare("SELECT * FROM users WHERE username = :username", array(":username" => "john_doe"));
?>
<pre><?php
print_r($users);
print_r($filtered_users);
?></pre>
Singleton design pattern is really useful when you want to make sure, that there's ONLY ONE instance of a class in any given time.
Related
Today I did some modifications into my database class. One of them was to use singleton pattern but I'm not 100% sure if i'm doing it right since I have never done this before.
It seems to work tho but still not sure if it does what's supposed to do.
Here is a sample. What do you think? Any suggestions are welcome :)
<?php
class Database {
protected static $instance;
private static $dsn = DB_TYPE.":host=".DB_HOST.";dbname=".DB_NAME;
private static $username = DB_USER;
private static $password = DB_PASS;
private function __construct() {
try {
self::$instance = new PDO(self::$dsn, self::$username, self::$password);
self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$instance->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $e) {
die($e->getMessage());
}
}
private function __clone() { }
public static function getInstance() {
if(!self::$instance) {
new Database();
}
return self::$instance;
}
public function read($query, $data = [])
{
$DB = Database::getInstance();
$stm = $DB->prepare($query);
if($stm) {
$check = $stm->execute($data);
if($check) {
$result = $stm->fetchAll(PDO::FETCH_OBJ);
}
}
}
if(is_array($result) && count($result) > 0) {
return $result;
}
return false;
}
}
// test
echo '<pre>';
print_r(Database::read("SELECT * FROM table"));
im new to PHP OOP, now i was woundering if there is a better way to use the Database Class then just extending it over all.
For Example i am having 3 main classes: Employee, Customer, Article. each of this classes have a subclasses which extends form. what i have done until now is extand the Db class on each of these 3 main classes.
My DB class:
class DbController{
private $serverName;
private $userName;
private $userPass;
private $dbName;
private $charSet;
private $pdo;
protected function __construct() {
try {
$this->serverName = "localhost";
$this->userName = "blabla";
$this->userPass = "***";
$this->dbName = "blabla";
$this->charSet = "utf8mb4";
$dsn = "mysql:host=".$this->serverName."; dbname=".$this->dbName."; charset=".$this->charSet;
$pdo = new PDO($dsn, $this->userName, $this->userPass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo = $pdo;
return $pdo;
} catch (PDOException $err) {
die($err->getMessage());
}
}
protected function getPdo(){
return $this->pdo;
}
public function __debugInfo(){
$properties = get_object_vars($this);
unset($properties['serverName']);
unset($properties['userName']);
unset($properties['userPass']);
unset($properties['pdo']);
unset($properties['dbName']);
unset($properties['charSet']);
return $properties;
}
}
one Of the Main classes (Employee):
<?php
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
include_once "DbController.cls.php";
class Employee{
public $id;
protected $name;
protected $username;
protected $scoore;
protected $dbTable = "employee";
protected PDO $pdo;
public function __construct($info = NULL) {
// pls notice that The DbController() is a protected Constructor.
$this->pdo = new DbController();
if (isset($info)) {
$this->id = $info["id"];
$this->name = $info["name"];
$this->username = $info["username"];
$this->scoore = $info["scoore"];
}
}
// Setters and Getters ......
then there is a sub class of Employee called EmployeeMng. this subclass contains functions such as login or signup. also this subclass handles the POST requests coming froom the client side.
include_once "../classes/Employee.cls.php";
$_POST = json_decode(file_get_contents('php://input'), true);
class EmployeeManagement extends Employee{
public function __construct() {
if (isset($_SESSION['empID'])) {
parent::__construct();
parent::__construct($this->fetchEmpInfo($_SESSION['empID']));
} else {
parent::__construct();
}
}
public function signIn($username, $password){
$retrunArray = array('code' => 0, 'msg' => "No Data Returned");
$checkCredential = $this->checkCredential($username, $password);
if ($checkCredential['code'] == 1) {
try {
$getEmpID = $this->pdo->prepare("SELECT `id` FROM `employee` WHERE `username`=? AND `password`=? LIMIT 1;");
$getEmpID->execute([$username, $password]);
$empId = $getEmpID->fetch(PDO::FETCH_ASSOC)['id'];
$_SESSION['empID'] = $empId;
$retrunArray['code'] = 1;
$retrunArray['msg'] = "Erfolgreich eingeloggt";
return $retrunArray;
} catch (PDOException $err) {
$retrunArray['code'] = 0;
$retrunArray['msg'] = $err->getMessage();
return $retrunArray;
}
} else{
// In case of DB Error
return $checkCredential;
}
}
// Request Handler Begin
$employeeService = new EmployeeManagement();
header('Content-Type: application/json');
// Login:
if (isset($_POST["signIn"])) {
$signIn = $employeeService->signIn($_POST["username"], $_POST["password"]);
echo json_encode($signIn);
}
Now i tried to declare the db class in the Employee constructor. but i keep getting the error Call to protected DbController::__construct() from scope Employee. is there a clean way to do that?
In general, you'd create your database object outside of this class and then inject it as a parameter. This is called Dependency Injection and is a Good Thing™.
Then you'd use that parameter within your class-specific methods. So your employee class would look something like this:
class Employee
{
protected $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
public function find($id)
{
// or whatever your query looks like
$stmt = $this->db->query('SELECT * FROM EMPLOYEE WHERE id = :id');
// $row = ...
return $row;
}
public function getAll()
{
$stmt = $this->db->query('SELECT * FROM EMPLOYEE');
// whatever
}
}
And then to use that class, you'd instantiate a database object, and then pass that to the Employee:
$db = new PDO();
$employee = new Employee($db);
$steve = $employee->find(1);
You should not do this:
class Employee
{
public $db;
public function __construct(PDO $db)
{
$this->db = $db;
}
}
$db = new PDO();
$employee = new Employee($db);
$steve = $employee->db->query('...');
Or this:
class Employee extends PDO
{
// ...
}
$employee = new Employee($db);
$employee->query('...');
Inheritance is not the way to go here. If you inherit DbController each class will instantiate a new PDO connection.
Instead, instantiate DbController first, then call its getPDO() method to obtain a PDO connection object to pass into your other classes as a parameter to their constructors. You'll need to change the DbController method declaration to public instead of private
Like this:
class DbController{
private $serverName;
private $userName;
private $userPass;
private $dbName;
private $charSet;
private $pdo;
public function __construct() {
try {
$this->serverName = "localhost";
$this->userName = "blabla";
$this->userPass = "***";
$this->dbName = "blabla";
$this->charSet = "utf8mb4";
$dsn = "mysql:host=".$this->serverName."; dbname=".$this->dbName."; charset=".$this->charSet;
$pdo = new PDO($dsn, $this->userName, $this->userPass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo = $pdo;
// return $pdo; No need for this. The constructor doesn't use it.
} catch (PDOException $err) {
die($err->getMessage());
}
}
public function getPdo(){
return $this->pdo;
}
}
class Employee {
private $PDO;
public function __construct(PDO $pdo) {
$this->PDO = $pdo
}
public function getEmployee($id) {
// get employee details using $this->PDO as your connection object
}
}
then your main program becomes something like
require_once('DbController.php');
require_once('Employee.php');
$DB = new DbController();
$emp = new Employee($DB->getPDO());
$id = 'some employee reference';
$employeeDetails = $emp->getEmployee($id);
I have a try catch block that connects via PDO to a database. I would like to be able to reference it in all my functions without having to pass it as a parameter. How would I do this? The mentioned code is:
try {
$database = new PDO('mysql:host=127.0.0.1;dbname=coop1','root','');
$database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e) {
echo $e->getmessage();
die();
}
EDIT:
I created a singleton class (attempt below) that executes the try catch block upon _construct
final class database {
private static $instance = NULL;
private function __construct() {
try {
$database = new PDO('mysql:host=127.0.0.1;dbname=coop1','root','');
$database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo $e->getmessage();
die();
}
}
public static function getInstance() {
static $instance = null;
if (self::$instance === NULL) {
$instance = new database();
}
return $instance;
}
}
Declare it as a static attribute of a singleten class. Than you can access it with
$pdo = Singleton::instance()->getConnection();
Alternatively I can suggest taking a look at MArtin Fowler's relational database mapping pattern. It goes a step further, than centralizing ony the connection itself.
Alternatively Doctirne project has a complete implementation of that: www.doctrine-project.org
final class database {
private static $instance = NULL;
private $pdo; //added private variable for pdo
private function __construct() {
try {
$database = new PDO('mysql:host=127.0.0.1;dbname=coop1','root','');
$database->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo $e->getmessage();
die();
}
$this->pdo = $database; //saved the connection into the new variable
}
public static function getInstance() {
static $instance = null;
if (self::$instance === NULL) {
$instance = new database();
}
return $instance;
}
//added a function to get the connection itself
function getConnection(){
return $this->pdo;
}
}
So now you use it:
$pdo = database::getInstance()->getConnection();
<?php
$mysql_host='mysql1.000webhost.com';
$mysql_dbname='a8130617_skola';
$mysql_username='something';
$mysql_password='something';
class mysql {
try{
public $db = new PDO("mysql:host=$mysql_host;dbname=$mysql_dbname",
$mysql_username, $mysql_password);
}
catch(PDOException $e){
echo $e->getMessage();
}
} //ERROR EXCLAMATION MARK HERE???
?>
why does netbeans 6.9.1 consider this to be false syntax?
many thanks
Do you know anything about OOP ?
Class should contain fields and/or methods. You just surrounded a piece of code with class{}. It is not programming.
Read about OOP in PHP - here is manual: http://php.net/manual/en/language.oop5.php
Read it for your own good.
Edit:
I know that following example can make you much lazy but I'll take a shoot and believe you will read more.
Example class for connections can look like:
class Mysql {
protected $_host;
protected $_dbname;
protected $_username;
protected $_password;
protected $_db;
public function __construct($host = null, $dbname = null, $username = null, $password = null)
{
$this->_host = $host;
$this->_dbname = $dbname;
$this->_username = $username;
$this->_password = $password;
}
public function connect()
{
try {
$this->_db = new PDO('mysql:host=' . $this->_host . ';dbname=' . $this->_dbname, $this->_username, $this->_password);
}
catch(PDOException $e){
echo $e->getMessage();
}
}
public function getDb()
{
return $this->db;
}
public function setHost($host)
{
$this->_host = $host;
return $this;
}
public function getHost()
{
return $this->_host;
}
public function setDbname($dbname)
{
$this->_dbname = $dbname;
return $this;
}
public function getDbname()
{
return $this->_dbname;
}
public function setUsername($username)
{
$this->_username = $username;
return $this;
}
public function getUsername()
{
return $this->_username;
}
public function setPassword($password)
{
$this->_password = $password;
return $this;
}
public function getPassword()
{
return $this->_password;
}
}
And example usage:
$mysql = new Mysql('mysql1.000webhost.com', 'a8130617_skola', 'something', 'something');
$mysql->connect();
try{
public $db = new PDO("mysql:host=$mysql_host;dbname=$mysql_dbname",
$mysql_username, $mysql_password);
}
catch(PDOException $e){
echo $e->getMessage();
}
Try catch blocks need to be inside a method. But going with that, not sure why you are wrapping this in a class? Your class is a wrapper for an already defined class.
OOP drives me crazy. I can't move PDO to work. Here's my DB class:
class DB extends PDO
{
public function &instance($dsn, $username = null, $password = null, $driver_options = array())
{
static $instance = null;
if($instance === null)
{
try
{
$instance = new self($dsn, $username, $password, $driver_options);
}
catch(PDOException $e)
{
throw new DBException($e->getMessage());
}
}
return $instance;
}
}
It's okay when i do something like this:
try
{
$db = new DB(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
}
catch(DBException $e)
{
echo $e->getMessage();
}
But this:
try
{
$db = DB::instance(DB_TYPE.':host='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
}
catch(DBException $e)
{
echo $e->getMessage();
}
Does nothing. I mean, even when I use wrong password/username, I don't get any exception.
Second thing - I have class which is "heart" of my site:
class Core
{
static private $instance;
public $db;
public function __construct()
{
if(!self::$instance)
{
$this->db = DB::instance(DB_TYPE.':hpost='.DB_HOST.';dbname='.DB_NAME, DB_USER, DB_PASS);
}
return self::$instance;
}
private function __clone() { }
}
I've tried to use "new DB" inside class, but this:
$r = $core->db->query("SELECT * FROM me_config");
print_r($r->fetch());
Return nothing.
$sql = "SELECT * FROM me_config";
print_r($core->db->query($sql));
I get:
PDOStatement Object ( [queryString] => SELECT * FROM me_config )
I'm really confused, what am I doing wrong?
Edit:
Ok, now I've got object as properity, however I still can't use query/exec.
Edit2:
I'm so dumb... The table doesn't have any records (only default values)
Try public static function &instance.