I want to access a connexion database through PDO in a static way but I am still getting an error. This is my code :
require_once 'include/class.Settings.php';
class MonthlySums{
protected static $dbh;
public function __construct() {
$user = Settings::$db['user'];
$pass = Settings::$db['password'];
$dsn = 'mysql:host=' . Settings::$db['host'] . ';dbname=' . Settings::$db['db'];
try {
self::$dbh = new PDO($dsn, $user, $pass);
} catch(PDOException $e) {
die("Error! : " . $e->getMessage());
}
}
public static function get($init_id) {
$sql = "SELECT `year`, `month`, `gains_monthly_sum` FROM `fxs_gain_sums` WHERE `init_id` = '$init_id'";
$resultats = MonthlySums::$dbh->query($sql);
var_dump($resultats);
}
}
I have this error :
Fatal error: Call to a member function query() on a non-object in /home/public_html/gainlosssums.php on line 45
That line is : $resultats = MonthlySums::$dbh->query($sql);
How to make it work a static way ?
When you call a static method in a class, the constructor is not automatically invoked like when you create an instance of the class. With your code you would have to create at least one instance of the class so that the database connection would be set in your static variable. Then you would be able to call it in your desired static way.
If you still want to continue with your code, you could change it to this:
(Please note: this is the OP's modified code and I am not going into other aspects - just the result to the OP's question/problem)
require_once 'include/class.Settings.php';
class MonthlySums{
protected static $dbh;
public function __construct() {
$this->databaseLogin();
}
public static function databaseLogin(){
$user = Settings::$db['user'];
$pass = Settings::$db['password'];
$dsn = 'mysql:host=' . Settings::$db['host'] . ';dbname=' . Settings::$db['db'];
try {
self::$dbh = new PDO($dsn, $user, $pass);
} catch(PDOException $e) {
die("Error! : " . $e->getMessage());
}
}
public static function get($init_id) {
$sql = "SELECT `year`, `month`, `gains_monthly_sum` FROM `fxs_gain_sums` WHERE `init_id` = '$init_id'";
$resultats = self::$dbh->query($sql);
var_dump($resultats);
}
}
MonthlySums::databaseLogin();
As you can see there is a new static method databaseLogin and is called right after the class declaration. This way the static variable for the database connection is set and can be used in other methods.
You now can call it this way:
MonthlySums::get(1234);
Again, this might not be best practice but a solution to your problem.
Related
I currently have a class which creates one database connection, however I would like to create another connection too. I have tried copying the class structure but just renaming the variables and functions however that doesn't work and it seems like it doesn't detect where my new PDO connection is as I get error Uncaught Error: Call to a member function prepare() on null in. What is the best approach to take in my case when creating 2 database connections?
config.php:
<?php
class Database
{
private $host = "localhost";
private $db_name = "database1";
private $username = "root";
private $password = "";
public $conn;
public function dbConnection()
{
$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;
}
}
?>
class.user.php:
class USER
{
private $conn;
public function __construct()
{
$database = new Database();
$db = $database->dbConnection();
$this->conn = $db;
}
public function runQuery($sql)
{
$stmt = $this->conn->prepare($sql);
return $stmt;
}
}
You could create your User class and pass the connection to the constructor. This will give you flexibility to swap out the connection.
Regarding your database class, it seems to be a wrapper, to create a PDO connection. You could do away with it, or extend the class with different params.
Perhaps look at dependency injection, and containers. They might help you here.
<?php
class User
{
private $conn;
public function __construct(PDO $conn)
{
$this->conn = $conn;
}
public function runQuery($sql)
{
$stmt = $this->conn->prepare($sql);
return $stmt;
}
}
When I attempt to connect to my SQL database with my pdo_object.php file, my model.php returns this error:
Fatal error: Class 'Db' not found in /path/model.php on line 8
I made sure all of the permissions are correct and credentials are correct for all of my files. Here are the two files in question.
Not really sure what the issue is here so any help would be awesome.
pdo_object.php
<?php
$user = 'someusername';
$pass = 'somepassword';
$db_info='somehost';
try {
$db = new PDO($db_info, $user, $pass);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
?>
and then model.php
<?php
include('pdo_object.php');
class Model{
public $db;
public function __construct(){
$this->db = Db::getDb();
}
public function getAllRecords($sql, $parameters = null){
$stm = $this->db->prepare($sql);
$stm->execute($parameters);
return $stm->fetchAll();
}
public function getOneRecord($sql, $parameters = null){
$stm = $this->db->prepare($sql);
$stm->execute($parameters);
return $stm->fetch();
}
}
?>
Where is class Db { //blah }? Nowhere. But you HAVE defined $db in the first file.
I also recommend dependency injection, rather than calling static class methods inside your class. Essentially, pass the $db in in the constructor:
public function __construct(PDO $db)
{
$this->db = $db;
}
And instantiate like so:
$model = new Model($db);
The Db class was not present in the pdo_object.php file, thus resulting in the index.php file throwing an error when referencing a non existing class.
class Db {
private static $db;
public static function getDb() {
if(!self::$db) {
try {
$dsn = 'somehost; dbname=somedbname';
self::$db = new PDO($dsn, 'username', 'password');
self::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
} catch (PDOException $e) {
die('Connection error: ' . $e->getMessage());
}
}
return self::$db;
}
}
I tried to run a query with PDO class and got this error message: "There is no active transaction" when trying to commit.
Here's my code:
public function runExQuery($sql) {
$preparedQuery = $this->connect()->prepare($sql);
$this->connect()->beginTransaction();
$preparedQuery->execute();
$this->connect()->commit();
}
private function connect() {
return new PDO('mysql:host=' . $this->host . ';dbname=' . $this->database . '', $this->username, $this->password);
}
What is the cause of this error? I explored previous posts of this type of question, but did not find any solutions.
Your ::connect() method is creating a new PDO each time you call it.
Since transactions do not survive outside of connections, the reconnecting wipes it out.
To correct this, store the PDO object as a class property:
class MyPdoClass
{
private $pdo;
// ...
public function connect()
{
if ($this->pdo instanceof PDO) {
return;
}
$this->pdo = new PDO(// ....
}
and then reference it after calling connect:
//...
public function runExQuery($query)
{
$this->connect();
$this->pdo->prepare($query);
// ...
}
You are creating a new PDO object every time you call $this->connect(), so if you have:
$stmt1 = $this->connect()->prepare(" ... ");
$stmt2 = $this->connect()->prepare(" ... ");
$stmt1 and $stmt2 will actually be completely different PDO objects, so if you start a transaction with one object, it will NOT apply to the other one. Instead you should save a PDO object and reference that instead of creating a new one every time.
Most of the time, I find it easier just to pass this to the class's constructor, however if you want to do minimal editing, you could just do:
class YourClass {
private $dbh;
private function connect() {
if (!isset($this->dbh)) {
$this->dbh = new PDO('mysql:host=' . $this->host . ';dbname=' . $this->database, $this->username, $this->password);
}
return $this->dbh;
}
}
However you might want to change the name connect() to something a bit more logical, like getDbh().
If instead you wanted to put it in the object's constructor, you could do this:
class YourClass {
private $dbh;
public function __construct(PDO $dbh) {
$this->dbh = $dbh;
}
}
$dbh = new PDO('mysql:host=' . $host . ';dbname=' . $database, $username, $password);
$yourclass = new YourClass($dbh);
Then in any of the other class methods, you would just reference $this->dbh. Using your code as an example:
public function runExQuery($sql) {
$preparedQuery = $this->dbh->prepare($sql);
$this->dbh->beginTransaction();
$preparedQuery->execute();
$this->dbh->commit();
}
Personally, this is the way I would do it.
I have been trying to get better at OOP. I am writing a database class, which will handle simply connecting to a database via PDO. Now, I want to make it so that it uses different variables if it is being served from my localhost server.
Consider the following code:
<?php
class Database {
private $host;
private $name;
private $username;
private $password;
public $conn;
if ($_SERVER['SERVER_NAME'] == "localhost") {
$host = "change_to_your_db_host";
$name = "change_to_your_db_name";
$username = "change_to_your_db_username";
$password = "change_to_your_db_password";
}
else {
$host = "change_to_your_db_host";
$name = "change_to_your_db_name";
$username = "change_to_your_db_username";
$password = "change_to_your_db_password";
}
public function connect () {
$this->conn = null;
try {
$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
}
catch (PDOException $exception) {
echo "Connection error: " . $exception->getMessage();
}
return $this->conn;
}
}
?>
I am very new to classes in general - I have been writing pure prodecural function-based PHP for wayyyy too long.
My questions are:
Is it cool to use $_SERVER variables within a class like that?
Is using that conditional statement within the class to determine the private variables OK? This class will be included in all of my other scripts which access the database via my object classes.
Is there a more efficient way to write this rather that have it echo an exception if one is caught?
I just want to make sure that I am doing things properly going forward. I have been writing PHP for a long time and I want to get out of the my outdated and archaic methods entirely.
You should do your conditional declaration in the __construct() method of your class like so:
<?php
class Database {
private $host;
private $name;
private $username;
private $password;
public $conn;
public function __construct()
{
if ($_SERVER['SERVER_NAME'] == "localhost")
{
$this->host = "change_to_your_db_host";
$this->name = "change_to_your_db_name";
$this->username = "change_to_your_db_username";
$this->password = "change_to_your_db_password";
}
else
{
$this->host = "change_to_your_db_host";
$this->name = "change_to_your_db_name";
$this->username = "change_to_your_db_username";
$this->password = "change_to_your_db_password";
}
}
public function connect () {
$this->conn = null;
try {
$conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
}
catch (PDOException $exception) {
throw $exception // you can throw again this \Exception to handle it in your code using the object
}
$this->conn = $conn;
return $this; // you should return $this so you can chain the object methods. Since $con is public, you can still access it
}
}
Is it cool to use $_SERVER variables within a class like that?
I cannot see why not.
Is using that conditional statement within the class to determine the private variables OK? This class will be included in all of my other scripts which access the database via my object classes.
As per #MarcB's comment, no you cannot run code at the top-level of a class, only in methods.
Is there a more efficient way to write this rather that have it echo an exception if one is caught?
Yes, throw it again so you can handle it in the final code using the Database class.
I am trying to call a function that is inside my Database class but I can't seem to get it right.
My Model class calls Database and assigns it to a variable:
class Model {
function __construct() {
$this->db = new Database();
}
function __destruct() {
$this->db = NULL;
}
}
I'm trying to call it from:
class User extends Controller {
function __construct() {
parent::__construct();
}
public function userExists($username) {
return $this->model->db->select('users', 'id', 'email LIKE ?', array($username));
}
}
But I keep getting the error:
Fatal error: Call to a member function select() on a non-object in C:\Apache24\htdocs\Manager 2014\controllers\User.php on line 10
My Database class is:
class Database extends PDO {
function __construct($user = 'root', $pass = '', $database = 'xxx', $host = 'localhost') {
try {
parent::__construct('mysql:host=' . $host . ';dbname=' . $database, $user, $pass);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$this->setAttribute(PDO::ATTR_PERSISTENT, FALSE);
$this->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$this->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
$this->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, FALSE);
$this->exec("SET NAMES utf8");
} catch (PDOException $e) {
Database::handleDbError($e);
}
}
public function select($table, $cols, $where = null, $whereVals = null, $order = null) {
if ($this->tableExists($table)) {
$PDOParams = array();
$SQL = 'SELECT ' . $cols . ' FROM ' . $table;
if ($where) {
$SQL .= ' WHERE ' . $where;
}
if ($whereVals) {
}
if ($order) {
$SQL .= 'ORDER BY ' . $order;
}
return $SQL;
} else {
}
}
public function tableExists($table) {
$r = $this->PDO->prepare("SHOW TABLES LIKE ?");
$r->execute(array($table));
return $r->rowCount();
}
}
What am I doing wrong?
If I:
print_r(get_class_vars ('UserModel'));
From the User class I get:
Array( [db] => )
Which doesn't make sense to me because that is being assigned in Model in the constructor that is being called when UserModel is called.
Instead of select() in my Database class, I now have the following in my main Model class:
public function get($primaryKeyId) {
$table = str_replace('model', '', strtolower(get_called_class()));
$SQL = "SELECT * FROM $table WHERE id = ?";
$r = $this->db->prepare($SQL);
$r->execute(array($primaryKeyId));
return $r->fetch();
}
There are many essential flaws with your implementation.
First and foremost, get rid of select() function
it's awfully insecure, allowing raw variables into query
it's fantastically inflexible, allowing only silly sandbox queries
it makes unreadable gibberish out of neat almost natural English of SQL
Second, do not create anew DB instance every time you invoke a class. Even simple app will kill your db server with that much number of connects.
pass db as a parameter into constructor instead
As it seems from your comment, errorhandler method doesn't handle anything which makes it evil
if you have no idea how to handle an error - just let it go. Get rid of this try/catch thingy completely
The database object in your model needs to be public so it can be accessed outside of the Model class.
class Model {
public $db;
function __construct() {
$this->db = new Database();
}
function __destruct() {
$this->db = NULL;
}
}
See object visibility for details on the difference between public, protected, and private.
I had just done a custom build of AMP and forgot to enable mysql PDO extension...That's why the DB parameter was empty FACEPALM.