Calling database set method inside construct - php

I am new to OOP so this is probably a simple solution. I am trying to clean up my code a little bit so that I don't have to do so much when I create an object. My code is below:
include "Database.php";
Class Database {
protected $conn;
public function setDb($conn){
$this->conn = $conn;
}
}
Class Images extends Database{
protected $conn;
protected $stmt;
function __construct(){
}
public function RetrieveImages(){
$this->stmt = $this->conn->prepare('SELECT * FROM `pictures`');
$this->stmt->execute();
$boom = $this->stmt->fetchAll();
return $boom;
}
}
$db = new Images();
$db->setDb($conn);
$test = $db->RetrieveImages();
var_dump($test);
Database.php:
try{
$conn = new PDO('mysql:host=localhost;dbname=testing', 'blah','boom!');
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
echo'ERROR: ' . $e->getMessage();
}
This code is working fine but I would like to automate the $db->setDb($conn); part. Is there a way I can call this automatically so I can initiate the object like
$db = new Images();
$db->RetrieveImages();
I have tried adding
$db = new Database();
$db->setDb($conn);
to the constructor method inside the Images class but I get an error
Call to a member function prepare() on non object
I tried several different ways to get this working but I am not able to do so.

Is there a way I can call this automatically so I can initiate the object
That's not a very desirable property of any code; it prevents testability of your code; ignoring the unfortunate naming of your classes I would set it up like this:
class Database
{
protected $conn;
public function __construct($conn)
{
$this->conn = $conn;
}
}
Then your Images class becomes:
class Images extends Database
{
public function RetrieveImages()
{
$stmt = $this->conn->prepare('SELECT * FROM `pictures`');
$stmt->execute();
return $stmt->fetchAll();
}
}
To call the whole thing:
// $conn was created in "Database.php"
$images = new Images($conn);
print_r($images->RetrieveImages());

Your Database class has no database anythings.
It does not do anything.
You need to have a MySQLi or PDO object somewhere to do databsse calls.

Related

Uncaught Error: Call to a member function prepare() on null in - PHP PDO OOPS [duplicate]

I think I've a problem in understanding how OOP works. I already changed the code that it works, but it isn't the propper way I think. Following scenario (No, I'm not creating a userlogin by myself, its really just for local dev. to understand OOP better):
I've a database.php file:
class Database {
/* Properties */
private $conn;
private $dsn = 'mysql:dbname=test;host=127.0.0.1';
private $user = 'root';
private $password = '';
/* Creates database connection */
public function __construct() {
try {
$this->conn = new PDO($this->dsn, $this->user, $this->password);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "";
die();
}
return $this->conn;
}
}
So in this class I'm creating a database connection and I return the connection (object?)
Then I have a second class, the famous User class (actually I'm not using autoload, but I know about it):
include "database.php";
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct() {
$this->conn = new Database();
}
/* Login a user */
public function login() {
$stmt = $this->conn->prepare("SELECT username, usermail FROM user");
if($stmt->execute()) {
while($rows = $stmt->fetch()) {
$fetch[] = $rows;
}
return $fetch;
}
else {
return false;
}
}
}
So thatare my two classes. Nothing big, as you see. Now, don't get confued about the function name login - Actually I just try to select some usernames and usermails from database and displaying them. I try to achieve this by:
$user = new User();
$list = $user->login();
foreach($list as $test) {
echo $test["username"];
}
And here comes the problem. When I execute this code, I get the following error message:
Uncaught Error: Call to undefined method Database::prepare()
And I'm not sure that I really understand what causes this error.
The code works well when I change the following things:
Change $conn in database.php to public instead of private (I think thats bad...? But when its private, I can only execute querys inside of the Database class, I'm right? So should I put all these querys in the Database class? I think that's bad, because in a big project it will get become really big..)
And the second change I've to do is:
Change $this->conn->prepare to $this->conn->conn->prepare in the user.php file. And here I've really no Idea why.
I mean, in the constructor of the user.php I've a $this->conn = new Database() and since new Database will return me the connection object from DB class, I really don't know why there have to be a second conn->
Do not create classes such as your Database class as it's rather useless. It would make sense to create a database wrapper if it adds some extra functionality to PDO. But given its current code, better to use vanilla PDO instead.
Create a single $db instance from either vanilla PDO or your database class.
Pass it as a constructor parameter into every class that needs a database connection
database.php:
<?php
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new \PDO($dsn, $user, $pass, $opt);
user.php
<?php
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct(\PDO $pdo) {
$this->conn = $pdo;
}
/* List all users */
public function getUsers() {
return $this->conn->query("SELECT username, usermail FROM user")->fetchAll();
}
}
app.php
include 'database.php';
$user = new User($pdo);
$list = $user->getUsers();
foreach($list as $test) {
echo $test["username"],"\n";
}
output:
username_foo
username_bar
username_baz
Check out my (The only proper) PDO tutorial for more PDO details.

Uncaught Error: Call to a member function query() on null in [duplicate]

I think I've a problem in understanding how OOP works. I already changed the code that it works, but it isn't the propper way I think. Following scenario (No, I'm not creating a userlogin by myself, its really just for local dev. to understand OOP better):
I've a database.php file:
class Database {
/* Properties */
private $conn;
private $dsn = 'mysql:dbname=test;host=127.0.0.1';
private $user = 'root';
private $password = '';
/* Creates database connection */
public function __construct() {
try {
$this->conn = new PDO($this->dsn, $this->user, $this->password);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "";
die();
}
return $this->conn;
}
}
So in this class I'm creating a database connection and I return the connection (object?)
Then I have a second class, the famous User class (actually I'm not using autoload, but I know about it):
include "database.php";
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct() {
$this->conn = new Database();
}
/* Login a user */
public function login() {
$stmt = $this->conn->prepare("SELECT username, usermail FROM user");
if($stmt->execute()) {
while($rows = $stmt->fetch()) {
$fetch[] = $rows;
}
return $fetch;
}
else {
return false;
}
}
}
So thatare my two classes. Nothing big, as you see. Now, don't get confued about the function name login - Actually I just try to select some usernames and usermails from database and displaying them. I try to achieve this by:
$user = new User();
$list = $user->login();
foreach($list as $test) {
echo $test["username"];
}
And here comes the problem. When I execute this code, I get the following error message:
Uncaught Error: Call to undefined method Database::prepare()
And I'm not sure that I really understand what causes this error.
The code works well when I change the following things:
Change $conn in database.php to public instead of private (I think thats bad...? But when its private, I can only execute querys inside of the Database class, I'm right? So should I put all these querys in the Database class? I think that's bad, because in a big project it will get become really big..)
And the second change I've to do is:
Change $this->conn->prepare to $this->conn->conn->prepare in the user.php file. And here I've really no Idea why.
I mean, in the constructor of the user.php I've a $this->conn = new Database() and since new Database will return me the connection object from DB class, I really don't know why there have to be a second conn->
Do not create classes such as your Database class as it's rather useless. It would make sense to create a database wrapper if it adds some extra functionality to PDO. But given its current code, better to use vanilla PDO instead.
Create a single $db instance from either vanilla PDO or your database class.
Pass it as a constructor parameter into every class that needs a database connection
database.php:
<?php
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new \PDO($dsn, $user, $pass, $opt);
user.php
<?php
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct(\PDO $pdo) {
$this->conn = $pdo;
}
/* List all users */
public function getUsers() {
return $this->conn->query("SELECT username, usermail FROM user")->fetchAll();
}
}
app.php
include 'database.php';
$user = new User($pdo);
$list = $user->getUsers();
foreach($list as $test) {
echo $test["username"],"\n";
}
output:
username_foo
username_bar
username_baz
Check out my (The only proper) PDO tutorial for more PDO details.

PDO FETCH_CLASS unexpected behaviour

I am trying to return a new instance of my User class via a DAO, and am struggling to see if it is working, it certainly isn't working as I expected, as I am not defining User properties, yet I am still seeing all the User fields and values from the database.
class Database
class Database
{
private $dbh;
public function __construct()
{
$this->openConnection();
}
private function openConnection()
{
try {
$this->dbh = new PDO('mysql:host=localhost; dbname=stats', 'user', 'pass');
$this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
'There was an error connecting to the database, error: ' . $e->getMessage();
}
}
public function query($sql, $params)
{
$stmt = $this->dbh->prepare($sql, $params);
$stmt->execute($params);
return $stmt;
}
}
class UserDao
class UserDao
{
private $db;
public function __construct($db)
{
$this->db = $db;
}
public function findById($ward_code)
{
$record = $this->db->query("SELECT * from ward_statistics where WardCode = :WardCode", array(':WardCode' => $ward_code));
$record->setFetchMode(PDO::FETCH_CLASS, 'User')
$user = $record->fetch();
return $user;
}
}
class User
class User
{
// with no properties defined, I still get a
// full result set from UserDAO::findById()
}
Usage
$db = new Database();
$dao = new UserDao($db);
$user = $dao->findById('AMED');
var_dump($user);
Results in an object with a full result set from the DB (a single row that is - matched by the WardCode), with all fields populated with the correct values (from the DB).
Whilst this seems OK - I thought that PDO::FETCH_CLASS required the properties to available within the class.
My worry is, from a question I posted on Code Review a few days ago, I was also told that class methods such as the findById one should create new class instances, or update the existing one, yet all I seem to be doing is retrieving a row from the database.
Thanks
Replace fetchAll with fetch if you need just 1 object. According to documentation:
PDOStatement::fetchAll — Returns an array containing all of the result
set rows

PHP/PDO how reuse connection started in a class to resolve "There is no active transaction" error

I have one class that encapsulate PDO defined as that example:
class db{
private $conn=null;
function __construct(){
getConn();
}
function getConn(){
$this->conn = new PDO("mysql:host=localhost;dbname=database", 'username', 'password');
}
}
I want reuse same db connection between different class instances so i can use transaction during complex operation like example:
function getDataFromAnotherTable(){
$db = new dbClass;
$data = execute('select * from table2');
return $data;
}
//main code start here...
$db = new db; //here i will instantiate class defined above
$db->beginTrans();
$db->execute(insert into table1);
//here transaction still active
$data = getDataFromAnotherTable()
//now transaction has been closed by previous call!
$db->execute('insert into table1');
//here i receive "There is no active transaction" error because transaction is closed inside
// getDataFromAnotherTable()
$db->endTransaction();
i want change my class like:
function __construct(){
if(empty($this->conn){
getConn();
}
}
So if a connection already exists, will be reused and no new connection will be created.
I've already tried this method but every instance of class obtain new connection so i can't reuse same connection to maintain my transaction over different classes and functions.
Please remember that this is only a simplified example! my situation is really more complex so i can't do a single insert statement using something like:
select x from table1 insert into table2
Thank you in advance for any support!
You could make $conn a static variable...
class myClass
{
private $conn = NULL;
function __construct()
{
static $nDB = false;
if ($nDB === false)
{
echo "INIT DB\n";
$nDB = true;
}
$this->conn = $nDB;
}
}
class myOne
{
private $oDB = NULL;
function __construct()
{
$this->oDB = new myClass();
}
}
class myTwo
{
private $oDB = NULL;
function __construct()
{
$this->oDB = new myClass();
}
}
$f1 = new myOne();
$f2 = new myTwo();
Should net you only one echo of
INIT DB
This is because the $conn is shared among all versions of myClass that are loaded.
You have 2 options basically.
First, if you have OOP exclusively all over the place, you have to pass PDO connection as a class property.
// having no class at hand I am passing $db into function as well
function getDataFromAnotherTable($db){
$data = $db->execute('select * from table2');
return $data;
}
$db = new db; //here i will instantiate class defined above
$db->beginTransaction();
$db->execute(insert into table1);
$data = getDataFromAnotherTable($db);
$db->execute('insert into table1');
$db->commit();
Second, you are mainly using old plain procedural style, then singleton would be the best answer. You'll only have to change -> to :: and get rid of this new dbClass; stuff:
function getDataFromAnotherTable(){
return DB::query('select * from table2')->fetchAll();
}
DB::beginTransaction();
DB::prepare("insert into table1 VALUES(?,?)")->execute([1,2]);
$data = getDataFromAnotherTable()
DB::prepare("insert into table1 VALUES(?,?)")->execute([3,4]);
DB::commit();

Database class, a data access object can't use a method of the database class

I created database class and a database access object so I can somehow Implement a value object pattern.
Here is some part of the database class and it's function:
class Database {
protected $conn = null;
private $stmt;
// create a connection
public function __construct($dsn, $username, $passwd) {
try {
// mysql and pdo
$this->conn = new PDO($dsn, $username, $passwd);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
$this->get_error($e);
}
}
}
Part of this db class is function I created called num_rows
public function num_rows($query) {
$this->stmt = $this->conn->prepare($query);
if ($this->stmt) {
$this->stmt->execute();
return $this->stmt->rowCount();
}
}
I also have this DAO class that does what you can actually see.
class Dao {
protected $db = null;
public function __construct() {
$dbh = new Database('mysql:host=localhost;dbname=doorche', 'root', '');
$this->db = $dbh->getConnection();
}
//put your code here
}
When I extend the DAO class in another class for example a loginDao I can't somehow access the *num_rows*
Why is that happening?
You need to inherit Dao class as below.
class Dao extends Database {
then in loginDao .
class loginDao extends Dao {
now loginDao can access Database methods too,

Categories