I've not written OOP code before, I always tried to avoid the extra keystrokes. Anyway, I'm taking the plunge as it's supposed to increase readability.
Anyway, I'm having trouble getting my classes to be able to access each other's methods.
Here's my setup:
$conf = new Conf(); // boot up!
// Include dependencies, system files and other functions
require_once $conf->getIncludePath() . 'error.php';
require_once $conf->getIncludePath() . 'pool.php';
require_once $conf->getIncludePath() . 'database.php';
require_once $conf->getIncludePath() . 'api.php';
require_once $conf->getIncludePath() . 'user.php';
require_once $conf->getIncludePath() . 'forms.php';
require_once $conf->getIncludePath() . 'page.php';
require_once $conf->getIncludePath() . 'resources.php';
$error = new Error();
$pool = new Pool();
$db = new Database();
$api = new Api();
$user = new User();
$forms = new Forms();
$page = new Page();
$resources = new Resources();
My question is, how do I get it so that a method in User class can run the query method inside Database, to say fetch their information?
I'm aware of using global $db; global $user; etc. inside every method ever, but isn't there a way for me to get to these variables without having to essentially redeclare them every time I want to use them?
Thanks
Piers
Using objects is so much more than just readability.
Without going into a full blown explanation of the reasons behind this, I highly recommend further research into the topic. Starting with why they are used and the problems that they resolve (and cause!).
As for your question:
You have a large number of objects that should really be able to 'talk' to each other.
We could say that the User class is dependent on the Database. To resolve this dependency we need to be able to reference the Database in the context on the User (the correct scope).
There are a few ways to accomplish this, however the common practice would be to define a member variable inside the User class and the set the value of the property using setters and getters. This is known to be injecting the dependencies.
For example:
class User {
protected $database;
public function getDatabase()
{
return $this->database;
}
public function setDatabase(Database $database) {
$this->database = $database;
}
public function getUsers()
{
$sql = 'SELECT * FROM user';
return $this->getDatabase()->execute($sql);
}
}
Your client code would then become:
$db = new Database();
$user = new User();
$user->setDatabase($db);
Please note that the above example is a contrived one at best - Making the User class depending on the Database would be a design decision that will cause you other problems further down the line - Something I think you need to research into.
Use dependency injection!
You could create a new class, DBHandler, that stores an instance of your Database class into every other class you want.
For example:
class DBHandler {
public static $db;
public static function init($db) {
self::$db = $db;
}
}
$db = new Database();
DBHandler::init($db);
Then you just need to inherit from this class, by using the extends keyword.
i.e.:
class User extends DBHandler {
// ... your code here ...
}
This is an example of how you could implement the dependency injection.
The __autoload() function
You don't need to require a class everytime you need if you use the __autoload() function.
For example, you can do this to automatically resolve dependencies:
function __autoload($classname) {
require_once $classname . ".php";
}
Following the tutorial at nettuts+ lead me to write this:
// load configuration
require_once 'includes/class.conf.php';
$conf = new Conf(dirname(__FILE__));
// dependency class
$conf->registerRequiredFile('dependencies');
$dependencies = new Dependencies();
// start registering dependencies
$conf->registerRequiredFile('error');
$error = $dependencies->error = function(){ // error
$error = new Error();
$error->conf = $conf;
return $error;
};
$conf->registerRequiredFile('pool');
$pool = $dependencies->pool = function(){ // error
$pool = new Pool();
$pool->db = $db;
$pool->user = $user;
$pool->error = $error;
// etc. any other dependencies
return $pool;
};
It works perfectly, the first conf file contains the registerRequiredFile method that then require_once a uri based on the parameter given.
Thanks for your help in pointing me in the right direction!
Related
As the title states; how can I use the HTMLPurifier library inside my class?
I'm trying to get to grips with OOP and PHP classes for the first time and have successfully built a class that connects to my database using my database class and returns a blog article.
I would now like to parse the HTML markup for the blog article using HTMLPurifier but I would like to achieve this inside my blog class and I'm wondering how it can be achieved, as HTMLPurifier is a class.
My class so far:
namespace Blog\Reader;
use PDO;
use HTMLPurifier_Config; <--- trying to include it here
use \Database\Connect;
class BlogReader {
private static $instance = null;
private static $article = null;
private static $config = null;
private static $db = null;
private static function InitDB() {
if (self::$db) return;
try {
$connect = Connect::getInstance(self::$config['database']);
self::$db = $connect->getConnection();
} catch (Throwable $t) {}
}
private function __construct($config) {
self::$config = $config;
}
public static function getInstance($config) {
if (!self::$instance) {
self::$instance = new BlogReader($config);
}
return self::$instance;
}
public static function getArticle($id) {
self::InitDB();
try {
if (self::$db) {
$q = self::$db->prepare("
// sql
");
$q->bindValue(':id', (int) $id, PDO::PARAM_INT);
$q->execute();
self::$article = $q->fetchAll(PDO::FETCH_ASSOC);
//////////// <----- and trying to use it here
$HTMLPurifier_Config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($HTMLPurifier_Config);
///////////
} else {
throw new Exception("No database connection found.");
self::$article = null;
}
} catch (Throwable $t) {
self::$article = null;
}
return self::$article;
}
private function __clone() {}
private function __sleep() {}
private function __wakeup() {}
}
However, I get the following error log when trying anything like this:
Uncaught Error: Class 'HTMLPurifier_Config' not found in
....../php/classes/blog/reader/blogreader.class.php
And the line number of the error is on this line:
$HTMLPurifier_Config = HTMLPurifier_Config::createDefault();
My class directory structure:
[root]
[blog]
blog.php <--- using classes here
[php]
afs-autoload.php
[classes]
[blog]
[database]
[vendor]
[htmlpurifier-4.10.0]
[library]
HTMLPurifier.auto.php <--- this is what I used to `include` on blog.php to autoload HTMLPurifier_Config::createDefault() and new HTMLPurifier($purifier_config).
My Autoloader (afs-autoload.php) file:
define('CLASS_ROOT', dirname(__FILE__));
spl_autoload_register(function ($class) {
$file = CLASS_ROOT . '/classes/' . str_replace('\\', '/', strtolower($class)) . '.class.php';
if (file_exists($file)) {
require $file;
}
});
I literally started learning classes today, so I'm really baffled as to how I can achieve this, especially with the namespace system I used.
I hope somebody with better experience can guide me in the right direction.
Rewritten answer:
1) Your auto loader is looking for <class>.class.php files; but your HTMLPurifier_Config is in a HTMLPurifier.auto.php file.
2) Still in your autoloader: str_replace('\\' You do not need to escape characters when in single quotes, so this should be: str_replace('\'.
3) This excellent answer should help you learn when and how to use the use PHP keyword.
4) Your issue is not the scope of your use (I don't think you even need to use use). But is that your autoloader is looking for the wrong type of files. Try manually loading the class using require and seeing if it works properly.
Original Answer
namespace Blog\Reader;
use PDO;
use HTMLPurifier_Config;
What you're actually doing here is using the values within the defined namespace; so you're using:
Blog\Reader\HTMLPurifier_Config
If you're HTMLPurifier_Config file is within its own namespace you need to specify that so that the "use" grabs the right data!
If its not in its own namespace then it will be in the global namespace which is identified with a slash:
namespace Blog\Reader;
use PDO;
use \HTMLPurifier_Config;
If it is in the namespace HTMLPurifier, for example:
namespace Blog\Reader;
use PDO;
use \HTMLPurifier\HTMLPurifier_Config;
to load the correct data reference.
Just to wrap this up, if you are using namespaces inside a class which as been placed in a namespace, this is how you create your purifier objects:
$config = \HTMLPurifier_Config::createDefault();
$purifier = new \HTMLPurifier($config);
$clean_html = $purifier->purify($dirty_html);
You do not have to use a use command since the HTMLPurifier classes themselves are not in a namespace. But when your code is in a namespace, you need to pre-pend '\' to non-namespaced classes.
namespace \Tdiscus; // This is the line that makes the difference.
use \Tsugi\Util\Net;
class Threads {
...
$config = \HTMLPurifier_Config::createDefault();
...
$retval = new \stdClass();
...
$dbh = new \PDO($dsn, $user, $password);
}
Because you placed the class in a namespace, any "non-namespaced" classes need a "" prefix - like PDO and stdClass in the above example.
The HTMLPurifier folks could have put their classes in a namespace - but they chose not to do that.
Using namespaces is a common practice when developing libraries intended for use with composer. But HTMLPurifier existed before composer was in common use and their classes have a nice unique prefix because they started out in a global class namespace - so they decided to leave well enough alone and not break the non-dynamic loading / non-namespace legacy adopters of their library.
I am wondering how i can store my connection in a class variable and then keep reusing it ? Right now my code looks like this
This function sets up my Connection right now and is called everytime
function setDB()
{
$serviceAccount = ServiceAccount::fromJsonFile('firebase_credentials.json');
$firebase = (new Factory)
->withServiceAccount($serviceAccount)
->create();
$db = $firebase->getDatabase();
return $db;
}
This is one of my functions which needs the connection $db to get and update Data.
function Period($gameid, $action)
{
$db = setDB();
$reference = $db->getReference('games/'.$gameid.'/Clock/CurrentPeriode');
$value = $reference->getValue();
if ($action =='m')
{
$value = $value -1;
$db->getReference('games/'.$gameid.'/Clock/CurrentPeriode')
->set($value);
} else {
$value = $value +1;
$db->getReference('games/'.$gameid.'/Clock/CurrentPeriode')
->set($value);
}
}
The solution is using Singleton pattern:
class DbConn
{
private $db;
protected function __construct()
{
$serviceAccount = ServiceAccount::fromJsonFile('firebase_credentials.json');
$firebase = (new Factory)
->withServiceAccount($serviceAccount)
->create();
$this->db = $firebase->getDatabase();
}
public function getInstance()
{
static $instance;
if (!$instance) {
$instance = new self();
}
return $instance;
}
public function getDb()
{
return $this->db;
}
}
And usage will be looking like this:
function Period($gameid, $action)
{
$db = DbConn::getInstance()->getDb();
$reference = .....
You can make setDB() into a singletron class and thus archive what you want.
Everyone here is saying use the singleton pattern. I'm going to say no don't use it as an answer: Read here and here.
Instead I would use a different approach: dependency injection. Use that paradigm and instantiate your classes upon initial load and then you use that to abstract your db layer from your logic making it easier to query rather than having to access that part every time you want to query or make changes like what you're doing now.
After all said and done, your logic should look something like this in the end:
// in your top configuration that gets loaded with your framework
// probably in it's own config file
$Factory = new Factory();
$serviceAccount = ServiceAccount::fromJsonFile('firebase_credentials.json');
$DbContext = new DbContext($Factory, $serviceAccount);
// somewhere in your app
$GamesRepository = new GamesRepository($DbContext);
// your logic in some function or part of the app
$gameId = 1;
$value = $GamesRepository->getCurrentPeriode($gameId);
$action == 'm' ? $value++ : $value--;
$GamesRepository->setCurrentPeriode($value, $gameId);
Because your repository is handling all the db conn stuff using another class that has the db connection handled from initial load of the page, you can just continue to use some kind of model or repository to fetch the info you need. I can expand on this but I think you should just think about your architecture a little and make a stab at it with what you know already if you decide the singleton pattern is not the best use case or want to try a different approach given it's downsides.
So I've come across a "problem" with PHP classes.
I have a few classes that require functions from one another, so at the moment I am doing the following:
$db = new blueConnect;
$core = new blueCore($db);
$users = new blueUsers($db, $core);
then within the file:
public function __construct(blueConnect $db, blueCore $core) {
$this->db = $db;
$this->core = $core;
}
However instead of doing this for each file that required additional functions, would it be better to write
global $db, $core
within each of the functions that require it?
The Name of the Pattern that you are talking about is called "Dependency Injection" or DI in short.
Depending on your Project using global might solve the problem in a short term but if you plan to create a big project that you later on test and share with multiple people you would like to avoid using global at all. - You can not test or debug that stuff well.
A (bad) solution is to make your database and core Class use the Singleton Pattern to avoid global but have the same effect. (not testable, not configurable)
public function __construct() {
$this->db = blueConnect::getInstance();
$this->core = blueCore::getInstance();
}
The solution for this is usually to create a Factory function that creates all of your Services that need the Database and the Core.
public function createService($name) {
$serviceClass = 'blue'.ucfirst($name).'Service';
return new $serviceClass($this->getDatabase(), $this->getCore());
}
And this Function is usually part of a Registry or better an DI Container like for example PIMPLE
Example with Only one Instance of each Service:
public function createService($name) {
$serviceClass = 'blue'.ucfirst($name).'Service';
static $services = array();
if(!isset($services[$name])) {
$services[$name] = new $serviceClass($this->getDatabase(), $this->getCore());
}
return $services[$name];
}
Be aware that you should NOT test with your Registry / DI Container since you have a "global" state inside of your container. (e.g. fetching the same service twice)
I would not use globals.
Reasons:
It's just not the OOP way.
Hard to debug.
The resulting code would not be testable. If you want your application to be covered by unit tests you should use Dependcy Injection as you currently do. I'll try to briefly explain why. Unit testing as its name implies is just that: testing a single unit of your application, i.e. your classes (their public methods).
Now let's suppose you use global variables that get set somewhere in your app. You won't be able to test your blueUsers class as a standalone unit because you will need the $db and $core objects to be instantiated. Therefore you won't be able to just include the blueUsers.php file and test the class because you will need other parts of your application (those which define the global variables $db and $core).
If on the other hand you used Dependcy Injection you wouldn't face such an issue. The only things you'll need to do in order to test the blueUsers class would be to include the class, create mocks of the dependencies $db and $core, and pass them to the blueUsers constructor.
Here's a nice source for more detailed explanation on how to write testable and maintainable code.
And here you could find more information about mocking and whether and what you can benefit from using it.
I'd use a singletone to contain the global objects. It's easily accessible by other objects and it provides a safe access to those variables:
final class GlobalObjects
{
public static function Instance()
{
static $inst = null;
if ($inst === null) {
$inst = new GlobalObjects();
}
return $inst;
}
private function __construct() {
$db = new blueConnect;
$core = new blueCore($db);
}
public function getDb() { return $this->db; }
public function getCore() { return $this->core; }
}
// ...
public function __construct() {
$this->db = GlobalObjects::Instance()->getDb();
$this->core = GlobalObjects::Instance()->getCore();
}
Another approach that comes into my mind, a simpler and dirtier one, is: as those variables are global objects it might be worth to define them as constants to avoid mistakes:
define( "db", new blueConnect );
define( "core", new blueCore($db) );
$users = new blueUsers($db, $core);
And then
public function __construct() {
global $db, $core;
$this->db = $db;
$this->core = $core;
}
If the parameters are dynamic and variable, you should pass them in constructor, so new blueUsers($db, $core, ...) is better. But if these are static parameter, and you don't need to pass them when initialization of the class, you should define as global.
What I'd like is to see the ideal framework for a system which has a group of objects (ie User) whereby the data is contained in a database. I've been advised to have a User class and a UserMapper class and this is my understanding of how it should look:
user.class.php
/* The class for constructing any user's information
*/
class User {
protected $userId, $email, $userGroup;
protected function getEmail() {
return $this->email;
}
protected function getUserId() {
return $this->userId;
}
public function __construct($userId, $email, $userGroup) {
$this->userId = $userId;
$this->email = $email;
$this->userGroup = $userGroup;
}
}
class UserMapper {
// database connection
private $db;
public function __construct($db)
{
$this->db = $db;
}
public function findByUserId ($userId) {
$userObject = new User();
$q = $this->db->prepare("SELECT userId, email, userGroup FROM user WHERE userId = :userId");
$q->bindValue(":userId", $id);
$q->setFetchMode( PDO::FETCH_INTO, $userObject);
$q->execute();
$q->fetch(PDO::FETCH_INTO);
return $userObject;
}
}
?>
main.php
<?php
include user.class.php;
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$getUser = new UserMapper($dbh);
$user = $getUser->findByUserId(41);
echo $user->getEmail();
?>
But this seems a bit messy in terms of the main.php side. Can I not make one PDO object and have that defined in all of my scripts? As well as a UserMapper object? Or do every time I want to get a user from the database do I need to make a NEW userMapper object, then do findByUserId (as above). Or is there a simpler way to doing this?
If I wanted to call a UserGroup object within the class User, how would I do this? (This would also need to connect to the database through PDO). To do the following seems messy:
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$getUserGroup = new UserGroupMapper($dbh);
$userGroup = $getUserGroupMapper->findByUserId($this->userGroup);
?>
one thing that i can think of is making this class a singleton, and create the $user above the declaration of the class, so whenever you include this class you'll have that user object.
Can I not make one PDO object and have that defined in all of my
scripts? As well as a UserMapper object?
You're actually looking for a Front Controller.
That is, in order to avoid the same instantiation of the same classes, you should have prepared them. Most people usually do this in bootstrap.php, that "tweaks" all required dependencies.
But a front controller implementation also includes a dispatcher and a router. I won't go deep into this, but focus on the problem you're trying to solve instead.
Factory pattern
It basically abstracts instantiation logic. The benefits are: 1) you can delay object instantiation 2) You avoid global state, which is bad for unit-testing. The simplified version of it would look like as:
class UserFactory
{
private $pdo;
private $cache = array();
public function __construct($pdo)
{
$this->pdo = $pdo;
}
public function build($mapper)
{
if (isset($this->cache[$mapper])) {
return $this->cache[$mapper];
} else {
// Inject an instance into a mapper
$instance = new $mapper($this->pdo);
// Save the state into a cache
$this->cache[get_class($instance)] = $instance;
return $instance;
}
}
}
And finally
A very simplified version of bootstrap-er would look like as,
<?php
/* File : bootstrap.php */
$dbh = new PDO('mysql:host=localhost;dbname=test', $user, $pass, array(PDO::ATTR_PERSISTENT => true));
// Include here UserFactory class
$userFactory = new UserFactory($dbh);
// Its kinda ready to be used
You would simply include in all scripts that need to access Users
<?php
/* File: main.php */
include(__DIR__ . '/bootstrap.php');
$getUser = $userFactory->build('UserMapper');
$user = $getUser->findByUserId(41);
echo $user->getEmail();
You need to use FETCH_CLASS instead and you don't need a userMapper just extend PDO then set the right fetch mode all in one class.
Don't forget to make the class definition available or use an autoloader
$this->statement->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE,"className");
FETCH_PROPS_LATE is there to get the constructor fired first in your class But you don't need a constructor in your case so just lose it. If you decide to keep it though than you should take a look here first.
Hope this helps good luck
I'm kinda new to PDO with MYSQL, here are my two files:
I have a connection class that I use to connect to the database:
class connection{
private $host = 'localhost';
private $dbname = 'devac';
private $username = 'root';
private $password ='';
public $con = '';
function __construct(){
$this->connect();
}
function connect(){
try{
$this->con = new PDO("mysql:host=$this->host;dbname=$this->dbname",$this->username, $this->password);
$this->con->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
echo 'We\'re sorry but there was an error while trying to connect to the database';
file_put_contents('connection.errors.txt', $e->getMessage().PHP_EOL,FILE_APPEND);
}
}
}
I have an account_info class that i use to query the data from the database:
class account_info{
function getAccountInfo(){
$acc_info = $this->con->prepare("SELECT * FROM account_info");
$acc_info->execute();
$results = $acc_info->fetchAll(PDO::FETCH_OBJ);
foreach ($results as $key) {
$results->owner_firstname;
}
}
}
I include both these files in my index.php page:
include_once 'classes/connection.class.php';
include_once 'classes/accountinfo.class.php';
$con = new connection();
$info = new account_info();
$info->getAccountInfo();
I just cant get it to work I'm not getting any output, I think it has something to do with the scope, but I don't know the correct why to fix it as I'm new to this PDO and OOP stuff.
Thanks in advance.
Solution 1
Replace class account_info { with class account_info extends connection {
Replace
$con = new connection();
$info = new account_info();
with
$info = new account_info();
and it should work.
Solution 2 (suggested)
I highly suggest you to solve your problem with dependency injection in this case.
Just replace your account class with:
class account_info {
private $con;
public function __construct(connection $con) {
$this->con = $con->con;
}
public function getAccountInfo(){
$acc_info = $this->con->prepare("SELECT * FROM account_info");
$acc_info->execute();
$results = $acc_info->fetchAll(PDO::FETCH_OBJ);
foreach ($results as $key) {
$results->owner_firstname;
}
}
}
and use it in index.php like this:
include_once 'classes/connection.class.php';
include_once 'classes/accountinfo.class.php';
$con = new connection();
$info = new account_info($con);
$info->getAccountInfo();
Explanation
As a general good rule: always specify the scope keyword for functions (public, protected or private).
The first solution is called inheritance and what we basically did was extending the account class with the connection class in order to inherit all the methods and properties from the connection class and easily use them. In this case you have to watch out for naming conflicts. I suggest you to take a look at the class inheritance in the PHP manual.
The second solution is called dependency injection and it is a wildly encouraged design pattern that makes your classes accept other classes in their constructor in order to explicitly define the class dependency tree (in this case account depend from connection and without the connection we can't make account work).
Another, of thousands of possible solution, would be the one that someone posted below which is a design pattern called Singleton. However that patter has been reevaluated recently as anti-pattern and should not be used.
A common method is to use a singleton pattern in your database class.
Something like this:
class connection {
private static $hInstance;
public static function getInstance() {
if (!(self::$hInstance instanceof self)) {
self::$hInstance = new self();
}
return self::$hInstance;
}
/* your code */
}
Then, you can simply use
$database = connection::getInstance();
$database->con->prepare(....)
etc