Reuse MySQL connection PHP object inheritance - php

I'm writing a single PHP script to migrate topics from an old forums site to a new one.
The old forums site use database "old_forums"
Thew new forums site use database "new_forums"
MySQL user "forums" has all privileges to both databases (I'm using 1 single user for convenience but I would not have any problems using 2 different users if required)
I have both forum hosted on the the same host - localhost
The script I have the following structure
<?php
class Forum {
//constants
const HOST = "localhost";
const DB_USER = "forums";
const DB_PASS = "forums";
...
//properties e.g. topic title, topic content
}
class OldForum extends Forum {
const DB_NAME_OLD = "old_forums";
public static function exportTopics() {
//some code
}
}
class NewForum extends Forum {
const DB_NAME_NEW = "new_forums";
public static function importTopics() {
//some code
}
}
OldForum::exportTopics();
NewForum::importTopics();
?>
I understand that I'm mixing procedural & object-oriented programming PHP (OOPP) here.
I'm new to object-oriented PHP but (I have experience with Java so I'm very open to some guide to make this pure OOPP)
I would like to ultilise 1 single MySQL connection for both OldForum and NewForum class.
Where should I instantiate a mysqli object?
e.g. inside Forum class' constructor or have a new mysqli object as a property of class Forum
so that I would create a new Forum object to initiate a MySQL connection
$a_forum = new Forum();

The mysqli connection is easy enough to share between instances by creating it once in your bootstrap file and then passing it to instances that need it, e.g.
$mysqli = new mysqli(/* connection params */);
$someClassUsingMySqli = new SomeClassUsingMySqli($mysqli);
$anotherClassUsingMySqli= new AnotherClassUsingMySqli($mysqli);
That will effectively limit the connection to one and you dont need to resort to globals inside your objects. This is called Dependency Injection and should be your prefered way of assigning dependencies to objects. It makes dependencies explicit and easy to swap out and thus benefits change, testing and maintenance.
As for your Import and Export Task, I wonder why you are doing this in PHP at all. It's apparently the same database server, so you could just do it inside your MySql instance. If you want to do it with PHP, I'd probably do something like this:
class MigrateForum
{
private $dbConnector;
public function __construct(DBConnector $dbConnector)
{
$this->dbConnector = $dbConnector;
}
public function migrate()
{
// orchestrate the migration (consider transactions)
$this->exportOldForum();
$this->importNewForum();
}
private function exportOldForum()
{
// code to export old_database_name.table_name
}
private function importOldForum()
{
// code to import new_database_name.table_name
}
}
You could extract the Import and Export methods into their own Classes and then use some sort of Composite Command Pattern, but that really depends on how modular you need this to be.

Different approach would be to create some VIEW in the new_forums database pointing to the old_forum database. In this case, all the "views" could have, for example, "old_" prefix? Something similar to this:
CREATE VIEW old_tbl_name AS
SELECT *
FROM old_forum.tbl_name
In such situation, you only have one connection to one database.

Related

Initialize php class with same name

If we have two or more classes with the same name, but in different folders, how would one differentiate between them during initialization?
require_once('database.php');
require_once('t/database.php');
$db = new Database(); // I want this to initialize the one in t/database.php
$globalDb = new Database(); // I want this to initialize database.php
This is what Namespaces are for.
But honestly, this sounds like an architectural problem. There are two ways you can approach this. If we were to answer your question as posed, you could solve your problem like so:
database.php
class Database{
// ...
}
t/database.php
namespace T;
class Database{
// ...
}
index.php
require_once('database.php');
require_once('t/database.php');
$db = new T\Database();
$globalDb = new Database();
But judging by your naming conventions, it appears as if you have two separate classes that are intended to interact with either the same - or similar - database instances.
I'm making some assumptions here, but the other way you can set up your logic is to condense your code down to a single Database class and operate on multiple connections over multiple instances.
Consider using dependency injection to manage your connections in a single unified class structure, especially if you're using the same type of RDBMS flavor across all connections.
Consider something like the following naive example:
class Database{
private $conn;
public function __construct(PDO $conn){
$this->conn = $conn;
}
public function select(...$args) { // Select Logic goes here }
public function insert(...$args) { // Insert Logic goes here }
public function update(...$args) { // Update Logic goes here }
public function delete(...$args) { // Delete Logic goes here }
}
It would be possible to operate over multiple connections at once by simply injecting different PDO instances into the same class:
require_once('database.php');
$conn1 = new PDO('mysql:host=localhost;dbname=test1', $user, $pass);
$conn2 = new PDO('mysql:host=localhost;dbname=test2', $user, $pass);
$db1 = new Database($conn1);
$db2 = new Database($conn2);
So while the first example may address your question directly, you may want to rethink your architecture if I'm on the right track with my second example.
And to echo everyone else, you should seriously consider using a proper Autoloader. Look into Composer and Autoloading - specifically PSR-4.
If we have two or more classes with the same name, but in different folders, how would one differentiate between them during initialization?
Don't do that. Loading the PHP file which contains the second definition will throw an error:
Fatal error: Cannot declare class Database, because the name is already in use
You will need to rename one of the classes.
As an aside, you may want to consider using an autoloader in your application instead of calling require() manually.

OOP PHP Can't get new mysqli from other class

I have class, where i make connection to database and do some queries.
But i can't make query to this database from other class. Problem is that class Cd can't see db connection command -> can't make a query. Here is the code:
require_once('config.php');
class myClass
{
public $mysqli;
public $res;
function connect()
{
$database = new Database();
$this->mysqli = new mysqli($database->db_host, $database->db_user, $database->db_pass, $database->db_table);
}
function cd($id)
{
......
}
}
}
class Cd extends myClass
{
function cdname($id)
{
$get= new Scandiweb();
$get->mysqli;
$this->res = $get->mysqli->query("SELECT * FROM disk WHERE id=" . $id . "");
if ($this->res->num_rows > 0) {
.........
}
}
}
Your code is a bit messy, so it's hard to tell where exactly the problem lies:
Why do you require config?
Why do you create a Database (which is more like a DbConfig) in the constructor instead of passing it?
What is the Scandiweb-class?
Why do you call mysqli->query on that class instead of $this
The last one is your immediate mistake. You extend myClass which creates the mysqli-connection and stores it as class variable $this->mysqli. That means that the child class Cd will have access to it. When you extend a class you can call all it's public and protected properties and methods. Only those marked as private can't be accessed.
That means instead of accessing $get->mysqli->query(...) you can do $this->mysqli->query(...). What would make sense in OOP is to create a connection once (like you do in the constructor) and pass it around to the services requiring a database connection. This is called Dependency Inversion Principle and using a Dependency Container makes it easier (but is not mandatory).
There are so called design patterns that will make it easier to deal with performing sql queries like in your code above. The most common ones are the Active Record-pattern as used in Laravel's Eloquent and the Propel library, the Table Data Gateway-pattern as used in Zend Framework's DB-component and the Data Mapper-pattern as employed by Doctrine ORM. If you want to write OOP code you should look at their documentation and maybe use one of those instead of dealing with everything yourself.

Constructing a site with classes

Recently I started looking more seriously into classes and OOP in general in PHP. I'm trying to create a simple site while taking advantage of classes as much as possible but there have been some questions that have been stuck in my mind.
More specifically I'd like to know how would a 'proper' site structure look like with classes and methods that deal with users, pages, menus, etc. Currently I'm using this wrapper to get around MySQLi more effectively and I can't seem to decide how should I implement this wrapper with other objects - do I create a new class for users, menus, etc. separately and just pass the database variable through the class every time I create an instance?
$db = new Mysqlidb (DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
$user = new User ($db);
Or do I just extend the SQL class as "models" like the wrapper's author has pointed out here.
Also in general, what should remain a class, what should I handle with only functions? How should I handle things with my MySQL class?
Is it a good practice to handle every single menu item/user/page as an object?
These are just some of the things confusing my mind right now. There are quite a few examples on the web about OOP but I still haven't found a decent one to explain the questions I asked above.
if you already familar with mysqlidb, its 2.1 and 2.2 releases are coming with a new dbObject class to implement models with some extra features.
Check out their https://github.com/avbdr/PHP-MySQLi-Database-Class/blob/master/dbObject.md
If you still want to stick with a pure MysqliDb classes you can try to do:
class Model {
protected $db;
public function __constuct () {
$this->db = MysqliDb::getInstance();
}
public function __call ($method, $arg) {
call_user_func_array (array ($this->db, $method), $arg);
return $this;
}
}
class user extends Model {
$this->tbl = 'users';
public function create ($data) {
$this->db->insert (...);
}
public function admins () {
return $db->where ("role", "admin")->get($this->tbl);
}
}
This will give you models like:
$user = new user ();
$q = $user->where('login','root')->admins();
Take a look at dbObject as its pretty simple and I bet it will do a job you need it to do.
As for OOP I would avoid storage of the mostly static content in the database.
Just split menus/sidebars/header/etc into separate subviews and you should be fine.

How to access the database class in OOP?

So I know that questions with 'what is the best' in their title aren't supposed to be asked, but really.. how should you do this?
We have a database class and, for example, a user class. A user class will get methods such as create() and update(), which will need to do database stuff.
As far as I know there are 2 main options, passing on the database object in every __construct() or make the database class static.
(Any other tips about OOP + database driven websites are also appreciated)
A very common pattern here is to make the database class a singleton construct, which is then passed to every object constructor (that is called Dependency Injection).
The purpose of making the database object a singleton is to ensure that only one connection is made per page load. If you need multiple connections for some reason, you would want to do it a different way. It's important to pass it via the constructors though, rather than creating the database object inside an unrelated class so that you can more easily test and debug your code.
// Basic singleton pattern for DB class
class DB
{
// Connection is a static property
private static $connection;
// Constructor is a private method so the class can't be directly instantiated with `new`
private function __construct() {}
// A private connect() method connects to your database and returns the connection object/resource
private static function connect() {
// use PDO, or MySQLi
$conn = new mysqli(...);
// Error checking, etc
return $conn;
}
// Static method retrieves existing connection or creates a new one if it doesn't exist
// via the connect() method
public static function get_connection() {
if (!self::$connection) {
self::$connection = self::connect();
// This could even call new mysqli() or new PDO() directly and skip the connect() method
// self::$connection = new mysqli(...);
}
return self::$connection;
}
}
class Other_Class
{
// accepts a DB in constructor
public function __construct($database) {
//stuff
}
}
// Database is created by calling the static method get_connetion()
$db = DB::get_connection();
$otherclass = new Other_Class($db);
// Later, to retrieve the connection again, if you don't use the variable $db
// calling DB::get_connection() returns the same connection as before since it already exists
$otherclass2 = new Other_Class(DB::get_connection());
Another method is to create your database class directly extending either mysqli or PDO. In that case, the __construct() method supplies the object to getConnect(), as in
public static function get_connection() {
if (!self::$connection) {
self::$connection = new self(/* params to constructor */);
}
return self::$connection;
}
Well, what you can do is to have the database access layer in one object, which is then passed to your objects, respecting the inversion of control pattern.
If you want to dig a bit into this direction, have a look into dependency injection (DI): http://en.wikipedia.org/wiki/Dependency_injection
Having a singleton is usually a bad idea as you will end up having problems when testing your code.
Having the database access logic within a model class such as User violates the separation of concerns principle. Usually DAO (Data Access Object) handles db related concerns.
There are ORM frameworks such as Hibernate, which handle mismatch between OO and relational models quite well, potentially saving a lot of manual work.
I'm really surprised that no one said this, but here it goes: ORM.
If your weapon of choice is PHP, then the major options are Propel and Doctrine. They both have many strengths and some weaknesses, but there's no doubt that they're powerfull. Just an example, from Propel's (my personal favourite) user manual:
// retrieve a record from a database
$book = BookQuery::create()->findPK(123);
// modify. Don't worry about escaping
$book->setName('Don\'t be Hax0red!');
// persist the modification to the database
$book->save();
$books = BookQuery::create() // retrieve all books...
->filterByPublishYear(2009) // ... published in 2009
->orderByTitle() // ... ordered by title
->joinWith('Book.Author') // ... with their author
->find();
foreach($books as $book) {
echo $book->getAuthor()->getFullName();
}
You won't get more OO than that!
They will handle a lot of things for you like for one, abstracting your data from the database vendor. That said, you should be able to move (relatively painlessly) from MySQL to SQL Server and if you're building your own tools for web applications, then beign able to adapt to different environments is a very important thing.
Hope I can help!
Hey have a look at ORM's. Let them do the hard work for you? fluent nhibernate or microsofts entity framework.
I could be misunderstanding your question. Sorry if so

PHP OOP: how to use a generic MySQL class in other classes

I've just started using OOP PHP and ran into a question. I've set up a generic mysql class that allows me to connect to a database and has some functions to obtain records from a table:
class mysql{
//some lines to connect, followed by:
public function get_record($sql)
{
$result = mysql_result(mysql_query($sql));
return $result;
//obiously it's a bit more advanced, but you get the picture.
}
}
Next, I have a class to obtain user details:
class user{
__construct($id)
{
$this->id = $id
}
public function get_username($id)
{
$username = get_record("SELECT name FROM users WHERE id = '".$this->id."'");
return $username;
}
}
I tried this, but got the error that the function get_record was unkown. I solved this by adding $mysql = new mysql(); to the user class.
However, it feels quite inefficient to have to instantiate the mysql object for every class that uses my database methods (that's pretty much all of them).
Is there a way to make the mysql class and its methods accessible to all other classes, without having to call the mysql class in every method?
For one, you don't need to use singleton in this case - or actually, you almost never do. See this article, for example.
Second, I think your OO designs are a bit off. The main point of object-oriented programming and design is to isolate responsibility into separate classes. Right now, you're giving your User class two main responsibilities - store / carry one user's relevant data, and query the data service (in this case, a simple MySQL / database abstraction layer).
You should first move that functionality into a separate object. Usually, this is called a Service - so in this case, it's a UserService. A UserService has one responsibility: provide access to User objects. So it'd sorta look like this:
class UserService {
public function __construct($mysql); // uses the mysql object to access the db.
public function get($id) {
$result = $this->mysql->get_record("select x from y");
$user = new User($result['id'], $result['name']); // assuming user has a constructor that takes an id and a name
return $user;
}
public function save($user);
public function delete($user);
}
You tie it all together at the start of your request (or where you need to access users):
$mysql = new MySQL($credentials);
$service = new UserService($mysql);
$user = $service->find(1337);
It's not perfect, but it's a much neater design. Your MySQL object does what it needs to do (build a connection, execute queries), your user object is plain dumb, and your service does only one thing, i.e. provide a layer between the actual storage layer and the thing calling it.
Design your mysql class to be called statically:
$username = Mysql::get_record("SELECT name FROM users WHERE id = '".$this->id."'");
http://php.net/manual/en/language.oop5.static.php
This is a common problem, and so there is a common solution to this.
As you might know, in software development common solutions on common problems are called Design Patterns.
There are two design patterns that can help you solve this problem.
In a more abstract sense the problem you are facing is:
How can i make class A available in class B?
The Singleton pattern
"In the singleton pattern a class can distribute one instance of itself to other classes."
This is not exactly what you are looking for, as your website may use multiple database connections. However, it is used by a lot of people in this way.
Read some information about using a singleton class as a database provider here:
https://www.ibm.com/developerworks/library/os-php-designptrns/#N10124
More information on the singleton pattern in PHP:
http://www.fluffycat.com/PHP-Design-Patterns/Singleton/
Another sensible approach is the registry pattern:
Registry Pattern
You can find information about the registry pattern on the link below, as well as an implementation almost identical that you are looking for:
http://www.sitecrafting.com/blog/php-patterns-part/
Even more powerful is a combination between the singleton and the registry.
Good luck and enjoy learning OOP PHP!
You should pass in the mysql object to each user object. So it would look like this:
$mysql = new mysql();
$user = new user( $mysql, $id);
$name = $user->get_username();
class user {
public function __construct($mysql, $id) {
$this->mysql = $mysql;
$this->id = $id;
}
public function get_username() {
$username = $this->mysql->get_record("SELECT name FROM users WHERE id = '".$this->id."'");
return $username;
}
}
using global variables, although that is probably not the best option.
$mysql = new mysql();
function someFunction() {
global $mysql;
$mysql->get_record(...)
}
or a static method for your mysql class (see Singleton)
class mysql {
public static $theInstance = new mysql();
public static function getInstance() {
return $this->theInstance;
}
}
function someFunction() {
$database= mysql::getInstance();
$database->get_record(...)
}
Start to think to use Doctrine, it's better
http://www.doctrine-project.org/

Categories