Class methods over different files - php

I am attempting to place a commonly used method (opendb) in the same class and file as my connect configuration file (connect.php) See fig A
class qcon{
public static $conn;
function dbcon()
{
if (empty($conn))
{
$host = 'x';
$username = 'x';
$password = 'x';
$dbname = 'x';
$conn = mysqli_connect($host , $username , $password ,$dbname) or die("Oops! Please check SQL connection settings");
}
return $conn;
}
function openDB($conn)
{
if (!$conn)
{
$this->error_msg = "connection error could not connect to the database:! ";
return false;
}
$this->conn = $conn;
return true;
}
Now I want to be able to pass the connection output of fig A so I can properly use the methods in another class file. Call it class.php. Here's one example function on class.php for viewing records. See fig. B
require_once("assets/configs/connect.php");
class dbcats {
var $conn;
function getResult(){
$result = mysqli_query($this->conn , "SELECT * from felines" );
if ($result) {
return $result;
}
else {
die("SQL Retrieve Error: " . mysqli_error($this->conn));
}
}
function closeDB() {
mysqli_close($this->conn);
}
Now, to get the call to work, Fig C below is where I'm at. I'm a tiny bit stuck.
$db1 = new qcon();
$helper = new dbcats();
$db1->openDB();
$helper = $db1;
$result = $helper->getResult();
So here we are. The logic is simple enough (I'll update the question if I'm not quite clear) So would someone advise on what amendments I need to get the call operational?

Orangepill's solution is fine and will more than likely get you going quickly. However, I would recommend making some minor alterations to your classes to allow you to more easily reuse their functionality across your programs.
Here, qcon holds your database connection information and functionality. It has a getter method, getConn() that allows you to get, and pass around that connection as you need.
class qcon
{
protected $conn;
public function __construct() { ... }
public function dbcon() { ... }
public function openDB() { ... }
public function closeDB() { ... }
public function getConn() { return $this->conn; }
}
Here's an example of an alternative dbcats class. It takes in your qcon class in part of its construction and holds it in as a protected member variable that it can use whenever it needs it. It also has getters and setters so that you can change or retrieve your database connection for this class at any time via getQConn() and setQConn().
class dbcats
{
protected $qcon;
public function __construct(qcon $q) { $this->qcon = $q; }
public function getResult() { ... }
public function getQConn() { return $this->qcon; }
public function setQCon(qcon $q) { $this->qcon = $q; }
}
It may not be the quickest fix, but I believe practices such as this will serve you better in the long-run.

From what I can see you are missing the end curly bracket } on both your classes. Everything would be much easier to see if you make the indentation correctly. That is, each time you have a left curly bracket { the following lines will be indented with one tab. Like this:
class qcon {
public static $conn;
function dbcon()
{
if (empty($conn))
{
$host = 'x';
$username = 'x';
$password = 'x';
$dbname = 'x';
$conn = mysqli_connect($host , $username , $password ,$dbname) or die("Oops! Please check SQL connection settings");
}
return $conn;
}
function openDB($conn)
{
if (!$conn)
{
$this->error_msg = "connection error could not connect to the database:! ";
return false;
}
$this->conn = $conn;
return true;
}
} <<< Missing this one
class dbcats {
var $conn;
function getResult(){
$result = mysqli_query($this->conn , "SELECT * from felines" );
if ($result) {
return $result;
}
else {
die("SQL Retrieve Error: " . mysqli_error($this->conn));
}
}
function closeDB() {
mysqli_close($this->conn);
}
} <<< Missing this one

You need to inject an instance of the qcon class into the dbcats class.
require_once("assets/configs/connect.php");
class dbcats {
var $conn;
public function __construct(qcon $dbconn){
$this->conn = $dbconn;
}
function getResult(){
$result = mysqli_query($this->conn , "SELECT * from felines" );
if ($result) {
return $result;
}
else {
die("SQL Retrieve Error: " . mysqli_error($this->conn));
}
}
function closeDB() {
mysqli_close($this->conn);
}
}
Then when you create an instance of dbcats pass in an instance of conn like ...
$db1 = new qcon();
$db1->openDB();
$helper = new dbcats($db1);
$result = $helper->getResult();

Related

Implementing mysqli procedural with a class

so recently I've been trying to use more procedural mysqli for practise, and have been looking at http://www.phpknowhow.com/mysql/mysqli-procedural-functions/, and also w3schools as reference, but i'm still having trouble so I thought I'd ask.
I have this database.php file where I have alot of stuff but the important stuff is
class Database{
public $host = DB_HOST;
public $username = DB_USER;
public $password = DB_PASS;
public $db_name = DB_NAME;
public $link;
public $error;
public function __construct(){
$this -> connect();
}
private function connect(){
$link = mysqli_connect($this->host,$this->username,$this->password,$this->db_name);
if(!$link){
echo "Failed".mysqli_error($link);
}
}
// create select method
public function select($query){
$result = mysqli_query($link,$query) or die("didnt work".mysqli_error($link));
if(mysqli_num_rows($result) > 0){
return $result;
}
else{
return false;
}
}
Now the way it currently works fine in my index.php file is simply by doing something like
$db = new Database();
//CREATe query
$query = "SELECT * FROM posts";
$posts = $db->select($query);
Is there any way to implement $posts = $db->select($query) with procedural functions? Before I have done stuff like mysqli_query($link,$query), but link is public here and inside a class so I can't do that, plus I want to access the function select . Thanks!
$link is not defined in your function select.
Modify your connect function:
private function connect() {
$this->link = mysqli_connect($this->host, $this->username, $this->password, $this->db_name);
if(!$this->link) {
echo "Failed: " . mysqli_error($this->link);
}
}
Now $this->link may be used in your select function:
public function select($query){
$result = mysqli_query($this->link, $query) or die("didn't work: " .mysqli_error($this->link));
if(mysqli_num_rows($result) > 0) {
return $result;
}
else{
return false;
}
}
I suggest you read the PHP OOP documenentation (at least the first chapters) to get a better understanding.

PHP Creating New Instance of a Class Returns NULL

I'm currently creating a really simplistic online ordering website as part of a school project. I am running into an issue where my controller tries to create an instance of a class that interfaces with my order parameters, but creating the new instance simply returns NULL. When the page where the operation is called loads, I receive this error:
Fatal error: Call to a member function getParameters() on null in /home/data/www/z1785732/public_html/467/PlaceOrderController.php on line 31
Here are the files I'm working with:
This is the controller. The specific class that is returning NULL is ParameterInterface.
<?php
include 'ItemDB.php';
include 'OrderDB.php';
include 'ccInterface.php';
include 'ParameterInterface.php';
class PlaceOrderController {
var $itemDB;
var $parameter;
var $orderDB;
var $ccInterface;
function __construct() {
$this->itemDB = new ItemDatabase();
$this->ccInterface = new ccInterface();
$this->parameter = new ParameterInterface();
}
public function displayCatalog() {
return $this->itemDB->displayCatalog();
}
public function searchItem($itemNum) {
return $this->itemDB->searchItem($itemNum);
}
public function getParameters() {
return $this->parameter->getParameters();
}
public function addOrder() {
$this->orderDB->addOrder($array1, $array2);
}
public function ccAuthorize($ccInfo) {
return $this->ccInterface->ccAuthorize($ccInfo);
}
}
?>
Here is ParameterInterface.php, where the function is defined.
<?php
class ParameterInterface {
function connect() {
$servername = '';
$dbname='';
$username = '';
$password = '';
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e){
echo "Connection failed: ". $e->getMessage();
}
return $conn;
}
public function getParameters() {
$conn = $this->connect();
$query = "SELECT * FROM Admin;";
$result = $conn->query($query);
$row = $result->fetch(PDO::FETCH_ASSOC);
return $row;
}
}
?>
I'm hoping it's just something simple that my eyes aren't catching. Any help would be greatly appreciated.
Thanks in advance!
Implement the Serializable interface to be able to serialize your controller in session:
class PlaceOrderController implements Serializable
{
// ...
public function serialize()
{
return serialize(array(
$this->itemDB,
$this->parameter,
$this->orderDB,
$this->ccInterface
));
}
public function unserialize($serialized)
{
list(
$this->itemDB,
$this->parameter,
$this->orderDB,
$this->ccInterface
) = unserialize($serialized);
}
// ...
}
Remember to start a new session after you do this. (clear your cookie) You may using an old PlaceOrderController object, with no propriety, in your current session.
Also, you may want rethink about this whole script. This isn't Java. Why you want store PlaceOrderController in session?
Your code seems clean enough to me... however; depending on the version of PHP you are using, the var Keyword might not be ideal here since it means Public. If your Member Variables are Public; getters and setters are really more or less not that necessary as such.
Back to the Issue. I would suggest taking a look at the name of the File: ParameterInterface.php because it may not have been properly included which might be a Typo or so in the Filename. Be mindful of cases (Upper & Lower - depending on your Operating System). Try first checking if the file exist to see what you get; like so:
<?php
if(file_exist("ParameterInterface.php")){
include "ParameterInterface.php";
die ("Sure, ParameterInterface.php exists and it has been included...");
}else{
die("Ah haaaa! Gotcha!!! So, 'ParameterInterface.php' does not exist in the current Directory....");
}
//AFTER THIS QUIRK DEBUGGING... YOU MIGHT JUST KNOW MORE...
Would You mind to try redefining your Class, instead? Like so:
<?php
class ParameterInterface {
/**
* #var PDO $CON_LINK
*/
protected static $CON_LINK;
//WOULDN'T HURT TO ADD AN EMPTY CONSTRUCTOR... NOW, WOULD IT?
function __construct(){
$servername = '';
$dbname = '';
$username = '';
$password = '';
if(!self::$CON_LINK) {
try {
self::$CON_LINK = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
self::$CON_LINK->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
}
}
function connect() {
return self::$CON_LINK;
}
public function getParameters() {
$conn = $this->connect();
$query = "SELECT * FROM Admin;";
$result = $conn->query($query);
$row = $result->fetch(PDO::FETCH_ASSOC);
return $row;
}
}
?>
Hope this helps a little...

Call to undefined function mysqli_result::num_rows()

I'm trying to count the number of rows in a result, and I keep getting the above returned error. I've checked the manual, and I'm using mysqli_result::num_rows() as I should be (I'm using object oriented style.) I've got three classes working here.
Class (Connection):
class utils_MysqlImprovedConnection {
protected $_connection;
public function __construct($host, $user, $pwd, $db)
{
$this->_connection = #new mysqli($host, $user, $pwd, $db);
if(mysqli_connect_errno ()) {
throw new RuntimeException('Cannot access database:' . mysqli_connect_error());
}
}
public function getResultSet($sql)
{
$results = new utils_MysqlImprovedResult($sql, $this->_connection);
return $results;
}
public function __destruct() {
$this->_connection;
}
}
Class (Handles Result):
class utils_MysqlImprovedResult implements Iterator, Countable {
protected $_key;
protected $_current;
protected $_valid;
protected $_result;
public function __construct($sql, $connection) {
if (!$this->_result = $connection->query($sql)){
throw new RuntimeException($connection->error . '. The actual query submitted was: '. $sql);
}
}
public function rewind()
{
if (!is_null($this->_key)){
$this->_result->data_seek(0);
}
$this->_current = $this->_result->fetch_assoc();
$this->_valid = is_null($this->_current) ? false : true;
}
public function valid()
{
return $this->_valid;
}
public function current()
{
return $this->_current;
}
public function key()
{
return $this->_key;
}
public function next()
{
$this->_current = $this->_result->fetch_assoc();
$this->_valid = is_null($this->_current) ? false : true;
$this->_key++;
}
public function count()
{
$this->_result->store_result();
$this->_result->num_rows();
}
}
Class function:
public function resetPassword($email, $pass){
//check if email exists, update authkey and password, send email
$sql = "SELECT * FROM table WHERE column = '$email'";
$results = $this->_db->getResultSet($sql);
if($results->count() == 1){
// Process
$this->_message = "Success!";
return $this->_message;
} else {
// Not unique
$this->_error = "Try again";
return $this->_error;
}
}
The test page I'm using to call all this is (include statement is just __autoload() function that is working fine):
$columnvar = 'emailaddress#test.com';
$pass = 'blah';
require_once 'inc.init.php';
$user = new utils_User();
try{
$string = $user->resetPassword($email, $pass);
echo $string;
}
catch(Exception $e) {
echo $e;
}
From the manual, it seems that mysqli_result::num_rows isn't a function, but rather a variable containing the number of rows.
It can be used like this:
$num_rows = $mysqli_result->num_rows;
The function equivalent is mysqli_num_rows($result), where you pass in the mysqli_result object, but that's if you're using the procedural style rather than object oriented style.
In your code, you should change your count() function in the utils_MysqlImprovedResult class to be like this (I'm assuming that's the function where you're getting the error message),
public function count()
{
// Any other processing you want
// ...
return $this->_result->num_rows;
}
or alternatively if you want to mix OO and procedural styles (probably a bad idea),
public function count()
{
// Any other processing you want
// ...
return mysqli_num_rows($this->_result);
}

Extending mysqli and using multiple classes

I'm new to PHP oop stuff.
I'm trying to create class database and call other classes from it. Am I doing it the right way?
class database:
class database extends mysqli {
private $classes = array();
public function __construct() {
parent::__construct('localhost', 'root', 'password', 'database');
if (mysqli_connect_error()) {
$this->error(mysqli_connect_errno(), mysqli_connect_error());
}
}
public function __call($class, $args) {
if (!isset($this->classes[$class])) {
$class = 'db_'.$class;
$this->classes[$class] = new $class();
}
return $this->classes[$class];
}
private function error($eNo, $eMsg) {
die ('MySQL error: ('.$eNo.': '.$eMsg);
}
}
class db_users:
class db_users extends database {
public function test() {
echo 'foo';
}
}
and how I'm using it
$db = new database();
$db->users()->test();
Is it the right way or should it be done another way?
Thank you.
You can do it that way, there's nothing wrong with that (I do something similar quite often). The only thing I would suggest is using exceptions instead of die (that way you can safely handle the error)...
protected function error($eNo, $eMsg, $extra = '') {
throw new Exception('MySQL error: ['.$eNo.'] '.$eMsg.': '.$extra);
}
Plus, I'd suggest overloading the query method as well
public function query($sql, $result_mode = MYSQLI_STORE_RESULT) {
$result = parent::query($sql, $result_mode);
if ($result === false) {
$this->error($this->errno, $this->errstr, $sql);
}
return $result;
}
I'd also suggest storing a copy of the $db object inside of the child class. So:
class db_users extends database {
protected $db = null;
public function __construct(Database $db) {
$this->db = $db;
}
public function test() {
echo 'foo';
}
}
Then, in __call:
if (!isset($this->classes[$class])) {
$class = 'db_'.$class;
$this->classes[$class] = new $class($this);
}
There is nothing wrong with this factory style for creating classes. I'd place a bit of exception handling in it.
My only other concern is extending database in your sub classes.
So I'd modify as follows:
public function __call($className, $args) {
if (!isset($this->classes[$class])) {
if(include_once('db_'.$class)) {
$class = 'db_'.$class;
$this->classes[$class] = new $class($this);
} else {
throw new Exception("Db class not found");
}
}
return $this->classes[$class];
}
And the users class as:
public class db_users {
private $db;
public __constructor($db) {
$this->db = $db;
}
public function test() {
return 'Foo';
}
}

Using a database class in my user class

In my project I have a database class that I use to handle all the MySQL stuff. It connects to a database, runs queries, catches errors and closes the connection.
Now I need to create a members area on my site, and I was going to build a users class that would handle registration, logging in, password/username changes/resets and logging out. In this users class I need to use MySQL for obvious reasons... which is what my database class was made for.
But I'm confused as to how I would use my database class in my users class. Would I want to create a new database object for my user class and then have it close whenever a method in that class is finished? Or do I somehow make a 'global' database class that can be used throughout my entire script (if this is the case I need help with that, no idea what to do there.)
Thanks for any feedback you can give me.
Simple, 3 step process.
1/ Create a database object.
2/ Give it to your user class constructor.
3/ Use it in the user methods.
Little example.
File Database.class.php :
<?php
class Database{
public function __construct(){
// Connects to database for example.
}
public function query($sqlQuery){
// Send a query to the database
}
[...]
}
In User.class.php :
<?php
class User{
private $_db;
public function __construct(Database $db){
$this->_db = $db;
}
public function deleteUser(){
$this->_db->query('DELETE FROM Users WHERE name = "Bobby"');
}
}
Now, in userManager.php for example :
<?php
$db = new Database();
$user = new User($db);
// Say bye to Bobby :
$user->deleteUser();
If you want the current trendy name of this old technique, google "Dependency Injection". The Singleton pattern in php will fade away soon.
As he said, put all your functions in the database class and use the database object to access those functions from your user class. This should be the best method in your case.
Eg:
global $database;
userclassvar = $database->doSomething();
What I like to do is make the database class with the Singleton pattern in mind. That way, if you already have a database object, it just retrieves it, otherwise creates a new one. For example:
Database.class.php
class Db
{
protected static $_link;
private function __construct()
{
// access your database here, establish link
}
public static function getLink()
{
if(self::_link === null) {
new Db();
}
return self::_link;
}
// etc.
}
User.class.php
class User
{
protected $_link; // This will be the database object
...
public function __construct()
{
$this->_link = Db::getLink();
}
}
And now you can use User's $_link property to do the database functions, like $this->_link->query(...). You don't necessarily have to put the Db::getLink() in the constructor if your class doesn't have to interact with the database that much.
Since you are using the database as an object, why not just add methods to the object that your "users class" can employ to take care of the things it needs to do. The users class can contain a pointer to the database class. The database class will protect your database, and assure that the users class is using it appropriately.
Here is a solution using PDO.
<?php
class Database {
private static $dbh;
public static function connect() {
$host = "mysql:dbname=YOUR_DB_NAME;host=YOUR_DB_SERVER";
$username = "YOUR_USERNAME";
$password = "YOUR_PASSWORD";
try {
self::$dbh = new PDO( $host, $username, $password );
self::$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
self::$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
self::$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
} catch( PDOException $e ){
$error_message = $e->getMessage();
exit();
}
return self::$dbh;
}
}
class MYObject {
public static $dbh = null;
public function __construct(PDO $db = null) {
if($db === null){
$this->dbh = Database::connect();
} else {
$this->dbh = $db;
}
}
}
class User extends myObject {
public function __construct($id = null, PDO $db = null) {
if($db === null){
parent::__construct();
} else {
parent::__construct($db);
}
if($id !== null){
return $this->select($id);
}
}
public function select($id) {
$retVal =false;
try {
$stmt = $this->dbh->prepare("SELECT...");
$stmt->execute();
if( $stmt->rowCount()==1 ){
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
$retVal =json_encode($row);
}
} catch (PDOException $e ) {
$error_message = $e->getMessage();
exit();
}
return $retVal;
}
}
?>
I think the better aproach would be to create the database class that instatiate right away on its own on a database.php and then include it on user.php. then every time you create a function that needs a database, you globalise the database object.
Check this.
databse.php
<?php
require_once ('includes/config.php');
class MysqlDb{
public $connection;
private $last_query;
private $magic_quotes_active;
private $real_escape_string_exists;
public function __construct() {
$this->open_connection();
$this->magic_quotes_active = get_magic_quotes_gpc();
$this->real_escape_string_exists = function_exists( "mysql_real_escape_string" );
}
public function open_connection() {
$this->connection = mysql_connect(DBHOST,DBUSER,DBPASS);
if(!$this->connection){
die("Could not Connect ".mysql_error());
}else{
$db = mysql_select_db(DB, $this->connection);
}
}
public function close_connection(){
if(isset($this->connection)){
mysql_close($this->connection);
unset($this->connection);
}
}
public function query($sql){
$this->last_query = $sql;
$results = mysql_query($sql, $this->connection);
$this->comfirm_query($results);
return $results;
}
private function comfirm_query($results){
if(!$results){
$output = "Query Failed " .mysql_error()."<br />";
$output .= "Last Query: " . $this->last_query;
die($output);
}
}
public function escape_value($value){
if( $this->real_escape_string_exists ) {
if($this->magic_quotes_active ) { $value = stripslashes( $value ); }
$value = mysql_real_escape_string( $value );
} else {
if( !$this->magic_quotes_active ) { $value = addslashes( $value ); }
}
return $value;
}
public function fetch_array($results){
return mysql_fetch_array($results);
}
public function num_row($results){
return mysql_num_rows($results);
}
public function insert_id(){
return mysql_insert_id($this->connection);
}
public function affected_row(){
return mysql_affected_rows();
}
}
$database = new MysqlDb();
?>
here is the user.php
<?php
require_once ('includes/database.php');
class User {
public $id;
public $fName;
public $lName;
Public $userName;
public $password;
public $email;
public $acess;
public static function find_all(){
global $database;
return self::find_by_sql("SELECT * FROM users");
}
public static function find_by_id($id=0){
global $database;
$results_array = self::find_by_sql("SELECT * FROM users where id={$id}");
return !empty($results_array)? array_shift($results_array) : false;
}
public static function find_by_sql($sql){
global $database;
$results = $database -> query($sql);
$object_array = array();
while($row = $database -> fetch_array($results)){
$object_array[] = self::instantiate($row);
}
return $object_array;
}
public static function instantiate($row){
$user = new self;
foreach($row as $attribute => $value){
if($user -> has_attribute($attribute)){
$user -> $attribute = $value;
}
}
return $user;
}
private function has_attribute($attribute){
$object_vars = get_object_vars($this);
return array_key_exists($attribute, $object_vars);
}
}
?>

Categories