I would like to share the parameters taken from a table in a db.
To take these parameters, I created a class made for this.
this is my scenario to share the parameters contained in a db between the various classes. is the correct approach to do this?
class Database
{
$private mys;
public function __construct()
{
$this->mys = new mysqli(....);
}
}
class params
{
$private db;
$public var1;
$public var2;
public function __construct()
{
$this->db = new Database();
}
public function getParams()
{
$result = $this->db->mys->query ("SELECT * FROM params");
while($row = $result->fetch_assoc())
{
$this->var1 = $row['var1'];
$this->var2 = $row['var2'];
}
}
}
class foo
{
private $db;
private $ps;
public function __construct()
{
$this->db = new Database;
$this->ps = new Params;
}
public function viewParams()
{
echo $this->ps->var1;
echo $this->ps->var2;
}
}
To access the private fields from other classes declare public 'getter' methods like:
public getVal1() {
return $this->val1;
}
In my modest opinion, there are various ways to share a parameters class with other classes. And they depends on how your system currently is and how it'll grow.
From what I learnt, a correct ways to pass dependencies to your classes is to inject they to the constructor, ex instead of:
class foo
{
...
public function __construct()
{
$this->db = new Database;
I would prefer to instanciate $db first:
$db = new Database();
and then
class foo
{
...
public function __construct(Database $db)
{
$this->db = $db;
This way your classes are loosely coupled and you can afford Unit Testing easily one day, working with interfaces and not concrete implementations, etc...please take a look at http://en.wikipedia.org/wiki/Dependency_injection
As a personal suggest I'll try to design the params class as an entity, mapped as a Db table object:
//entityParams.php
class EntityParams
{
private $id; //column name
private $columnA;
private $columnB;
public function setId($id)
{
$this->id = $id;
}
public function setColumnA($columnA)
{
$this->columnA = $columnA;
}
...
}
then use a Database class as a simple connector class (just to promotes single-responsibility and separation of concerns):
//Database.php
class Database
{
private $dbh = NULL;
public function connect()
{
$this->dbh = new Mysqli(...);
}
public function getConnection()
{
if(is_null($this->dbh))
{
$this->connect();
}
return $this->dbh;
}
}
and use a DatabaseManager instead, to let it do all dirty works.Something like:
//DatabaseManager.php
class DatabaseManager
{
private $db;
private $entities = array();
private $currentEntity;
public function __construct(Database $db)
{
$this->db = $db;
}
public function fromEntity($entityName)
{
$entityClass = "Entity".ucfirst($entityName);
if(!isset($this->entities[$entityClass]))
{
$this->entities[$entityClass] = $entityName;
}
$this->currentEntity = $entityClass;
return $this;
}
public function getAll()
{
$results = $this->db->getConnection()->query("SELECT * FROM {$this->entities[$this->currentEntity]}");
$entities = array();
foreach ($results->fetch_all(MYSQLI_ASSOC) as $key => $item)
{
$e = new $this->currentEntity;
$e->setId($item['id']);
$e->setColumnA($item['columnA']);
$e->setColumnB($item['columnB']);
$entities[] = $e;
}
return $entities;
}
Finally your Foo class (and everyone else) just has a simple dependency with the DatabaseManager (which could evolve as a RespositoryManager):
//Foo.php
class Foo
{
public $dbm;
public function __construct(DatabaseManager $dbm)
{
$this->dbm = $dbm;
}
public function viewParams()
{
return $this->dbm->fromEntity("params")->getAll();
}
public function viewParam($id)
{
return $this->dbm->fromEntity("params")->find(2);
}
}
//client.php
/* Here you can instantiate the classes and pass they through constructor or investigate on how to create and use a Dependency Injection Container */
$db = new Database();
$dbm = new DatabaseManager($db);
$foo = new Foo($dbm);
var_dump($foo->viewParams());
var_dump($foo->viewParam(1));
I just wrote simple basic ideas that could be worth to play around it and improve it.
Related
I have a single class that calls aload of other classes;
require_once('class.database.php');
require_once('class.users.php');
Class Bootstrap {
public $db;
public $users;
public function __construct() { $this->db = new Database(); $this->users = new Users(); }
}
$est = new Bootstrap();
And that class works fine, but lets say in my Database class I have;
class Database {
public function __construct() { }
public function foo() {
echo 'hi';
}
}
And then from the users class, I'd like to reference the function, but I wanna keep the code clean and therefore want to steer away from statics.
I've tried referencing it such as:
* $est->db->foo();
* $db->foo();
But none of them work, could somebody please show me the correct way to call it. Thanks!
Currently you have given yourself no way to access the specific db instance inside Bootstrap from within the Users class.
You could:
Hand the db instance to Users when you instantiate:
$this->users = new Users($this->db);
Hand the Users class a reference to Bootstrap when you instantiate:
$this->users = new Users($this);
Have the users class setup its own database connection:
class Users { public function __construct() { $this->db = new Database(); } }
Setup statics
You could give your classes a refference to the bootstrap and fetch them that way or make your bootstrap a singleton:
require_once('class.database.php');
require_once('class.users.php');
Class Bootstrap {
public $db;
public $users;
public function __construct() { $this->db = new Database($this); $this->users = new Users($this); }
}
$est = new Bootstrap();
And in your classes
class User {
private $bs;
public function __construct($bs) { $this->bs = $bs}
public function foo() {
$this->bs->db->foo();
}
}
Or Bootrap as a singleton:
require_once('class.database.php');
require_once('class.users.php');
Class Bootstrap {
private static $instance=null;
public $db;
public $users;
private function __construct() { $this->db = new Database($this); $this->users = new Users($this); }
public static function getInstance(){
if(!self::$instance){
self::$instance = new self();
}
return self::$instance;
}
}
$est = Bootstrap::getInstance();
And in user:
class User {
public function __construct() { }
public function foo() {
$db = Bootstrap::getInstance()->db;
$db->foo();
}
}
I have
class Check
{
public function __construct()
{
$this->db = new Database();
}
public function query()
{
$login = Session::get("login");
$sth = $this->db->prepare('SELECT admin FROM accounts WHERE login=:login');
$sth->execute(array(':login' => $login));
$result = $sth->fetch(PDO::FETCH_NUM);
return $result[0];
}
public static function admin()
{
echo self::query();
}
}
I have Database class in another place with PDO connection.
class Database extends PDO
{
public function __construct()
{
parent::__construct('mysql:host=localhost;dbname=name','root','pass');
$this->query('SET NAMES utf8');
}
}
So after Check::admin() code I get error:
Undefined property: View::$db
Why?
You are using a static method, that wants to use a instance variable.
Your admin method calls the query method, and the query method is using the db instance variable. As your class is not instantiated, the db variable does not exists.
My suggestion would be to make the admin method non static and use your code like this:
$mycheck = new Check();
$mycheck->admin();
or, if you are on php 5.4 and want to stick with a oneliner:
(new Check())->admin();
update
note: Do not create the db class in the constructor, but inject it:
public function __construct(Database $db)
{
$this->db = $db;
}
Sorry this is not direct answer for your question but your code has some issues so take some time and examine this and ask if it's not clear for you.
<?php
class Check {
protected $_db;
public function __construct(Database $db) {
$this->_db = $db;
}
public function query(ISession $sessionData) {
//WHY IS THE SESSION STATIC?
//$login = Session::get("login");
$sth = $this->_db->Connection()->prepare('SELECT admin FROM accounts WHERE login=:login');
$sth->execute(array(':login' => $sessionData->get("login")));
$result = $sth->fetch(PDO::FETCH_NUM);
return $result[0];
}
public function admin(ISession $sessionData) {
// REALLY BAD TO ECHO HERE
echo $this->query($sessionData);
}
}
class Database {
private $_name;
private $_password;
private $_connStr;
private $_settings;
private $_pdo;
public function __construct($connstr, $name, $password, array $settings = array()) {
$this->_name = $name;
$this->_password = $password;
$this->_connStr = $connstr;
$this->_settings = $settings;
}
public function Connection() {
if ($this->_pdo == NULL) {
$this->_pdo = new PDO($this->_connStr, $this->_name, $this->_password);
}
return $this->_pdo;
}
/* other fancy methods */
public function Close() {
$this->_pdo = NULL;
}
public function __destruct() {
$this->Close();
}
}
And i don't see why you need a Check class for all this becouse if i were you i would create somethinf like this:
$currentSession = Session::GetCurrent();
$currentSession->User()->IsInRole('admin');
Note that the session is not static and if i would write a more complete solution i would avoid Session::GetCurrent() call becouse the current session would be a field in some class' instance (HttpApplication for example).
I'm trying to pass a PDO connection object from one class to another. But I'm not being very successfull. And I only want to instanciate only one PDO object.
With the help from dqhendricks and awm I managed to get the following solution working:
class Factory {
function createUser($id = NULL) {
return new User(Conn::get_conn(), $id);
}
function createApplication($id = NULL) {
return new User(Conn::get_conn(), $id);
}
}
class Conn {
private static $conn = NULL;
private function __construct() {}
private static function init() {
$conf = self::config();
try {
self::$conn = new PDO($conf['dsn'], $conf['user'], $conf['pass']);
}
catch (PDOException $e) {
echo $e->getMessage();
}
}
public static function get_conn() {
if (!self::$conn) { self::init(); }
return self::$conn;
}
private static function config($cfg_file = 'sl.config') {
$config = parse_ini_file('/../'.$cfg_file);
$conf = array();
$conf['user'] = $config['db_user'];
$conf['pass'] = $config['db_password'];
$conf['dsn'] = 'mysql:dbname='.$config['db_name'].';host='.$config['db_host'];
return $conf;
}
}
In my UserDAO class, I can now do this:
class UserDAO {
private $db;
private $id;
function UserDAO (&$db, $id) {
$this->db = &$db;
$this->id = &$id;
}
public function getRows($sql)
{
$result = $this->db->query($sql);
$row = $result->fetch(PDO::FETCH_ASSOC);
return $row;
}
function getUsers($limit = 10) {
$sql ="SELECT * FROM sl_store LIMIT $limit";
return $this->getRows($sql);
}
}
//My User class
class User extends UserDAO implements iUser {}
// And to test it working:
$user1 = Factory::createUser('5');
$user2 = Factory::createApplication('7');
How about defining an abstract class which gives you the PDO object on request?
E.g.
abstract class Db {
private static $x = null;
private static function init() {
try {
self::$x = new PDO(...);
} catch (PDOException $e) {
...
}
}
public static function getX() {
if (!self::$x) self::init();
return self::$x;
}
}
no need to have your class create an instance of itself if all you want is an instance of a different object back. maybe make a static method in Conn to return an instance of a db connection.
class Conn {
// prevent new statement
private __construct() {}
public static return_pdo() {
blah
blah
blah
return $db;
}
public static config($file) {
do stuff
}
}
then call statically
$pdo = Conn::return_pdo();
It's because new Conn() returns $Conn object, not the value from $Conn->Conn() method.
Try this:
class Conn{
function Conn() {
$db = new PDO($conf['dsn'], $conf['user'], $conf['pass']);
}
function get_db() {
return $this->db;
}
}
class Factory {
function createUser($id = NULL) {
$new_conn = new Conn();
$db = $new_conn->get_db();
}
}
Hope you can help me with this one: i have two classes: Database and Users. The Database connects to the database using PDO (inside the constructor) and has functions to alter tables, insert data, etc. The Users class will handle login, as well add/remove users. However, the Users class needs to connect to the database. How can i do this?
There are several things you could do:
Globals
$db = new Database();
class Users
{
public function foo()
{
global $db;
$db->query();
}
}
Setting a static variable
$db = new Database();
class Model
{
static public $db;
}
Model::$db = $db;
class Users extends Model
{
public function foo()
{
self::$db->query();
}
}
Use a singleton
class Database
{
private static $instance;
private function __construct()
{
}
public static function instance()
{
return self::$instance ? self::$instance : self::$instance = new self();
}
}
class Users
{
public function foo()
{
Database::instance()->query();
// or $db = Database::instance(); $db->query();
}
}
The one thing you want to avoid is creating a new database connection per model or class.
Same way you normally would, but it might help to make the database a class property:
<?php
class Users
{
protected $_db;
public function __construct(Database $database = null)
{
if (!$database) {
$database = new Database;
}
$this->_db = $database;
}
public function addUser($username)
{
// Do stuff ...
$this->_db->insert($data);
}
}
Then you can use the User class like:
<?php
$users = new Users;
$users->addUser('joebob');
Simply add a reference to the database class instance into Users:
class Users {
var $database;
function __construct() {
$this->database = new Database();
}
};
Alternatively, if Database is a singleton, just reference it directly.
One way to do so would be to create ONE shared instance of the database class, then use it as a global variable wherever needed.
Start by creating the instance anywhere in your project, just make sure it is in global space (not inside another class or function).
$DB = new Database();
Then to access the shared database object, just use the $GLOBALS built-in array:
class User {
function __construct() {
$DB = &$GLOBALS['DB'];
// do something
$DB->callSomeMethod();
}
...
}
As pointed out by #Ryan, namespace collisions are possible using this strategy. The best middle path out would be to convert the Database class into a singleton. Then it would store its own instance (translation: ONE connection no matter what) which could be accessed via a Database::getInstance() method.
This is my Users class:
class Users {
private $data;
private $db;
public function __construct() {
$db = Database::getInstance('localhost', 'database', 'root', '123456');
}
public function __get($key) {
return $this->data[$key];
}
public function __set($key, $value) {
$this->data[$key] = $value;
}
public function test() {
foreach($this->db->query('table', '*', '', '', '', '', '0,5') as $value) {
$results .= $value['field1'] . "<br />";
}
return $results;
}
}
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';
}
}