I'm writing a web reporting extension to a data warehouse my company purchased. The data warehouse is data-model neutral, and has tables storing the table relationships and metalayer data for the fields. This makes it pretty easy for me to write a basic ORM class, which is what I'm trying to do. It all works, but...
My ORM class holds the PDO instance, the fields for the table (used as a whitelist), and metalayer info for the fields. It also has convenience functions for mapping the table relationships (generates the FROM / JOIN clauses) and mapping the filters supplied from the web (generates the WHERE clause).
The SELECT clause is generated in child classes of the ORM, based on the model requested. When the page loads, there are several models that need to be built. Obviously, I only need one instance of the ORM (like a monostate), but I would like each child class to inherit the properties and convenience functions of the ORM -- without redoing the parent class' queries each time a child class is instantiated.
The singleton pattern may fit here, but I'm finding it difficult to subclass a singleton. And I just can't seem to get static properties to work right.
I think I'm close but I'm either missing something or making this too difficult. I'm now considering dropping the properties into a thin class and extending from there while mixing the convenience function in with traits. I've seen similar questions for this topic, but haven't come up with a definite solution.
I'm not at work, but this is a simplified example of the code that should give you the gist of what I'm trying to do.
Class ORM {
protected $conn;
protected $fields;
protected $relations;
protected $table;
protected $sql;
public function __construct ($view, $database) {
$this->conn = new PDO(...$database...);
$this->table = $view;
$this->getFields();
$this->getRelations();
}
private function getFields () {
//select fields from metalayer where table = $table;
//$this->fields = $result;
}
private function getRelations () {
//select relations from relations where table = $table;
//$this->relations = $result;
}
protected function mapTables ($tables) {
// $this->sql = "FROM $this->table";
// foreach ($tables as $table) {
// $this->sql .= "LEFT JOIN $table ON $relations[$table]['key1'] = $relations[$table]['key2'];
}
protected function mapFilters ($filters) {
// $this->sql = "WHERE 1=1";
// foreach $filters as $filter {
// $this->sql .= "AND ($filter['field'] = $filter['criterion1'] OR ...criterion2, etc.)
}
}
Class ExampleModelDAO extends ORM {
public function __construct($view, $database, $params) {
parent::__construct($view, $database);
// parse params
parent::mapTables($tables);
parent::mapFilters($filters);
}
public function get() {
// Prepend $this->sql with SELECT statement specific to model
// Query database and return model
}
}
First off, your orm/model shouldn't know anything about the database. There are a million ways to do this but I would start with a simple database class that offers some additional functionality on top of pdo but completely independent from anything else. This will also allow you to do direct database access without requiring the need for a model as well as allow you to create models that are database independent. For maximum flexibility you want to look into the adapter pattern and data mapper. However, to keep it simple, here is a very basic example (without an adapter or data mapper) of mapping a model to a data store.
<?php
class DB extends PDO {
public function __construct() {
try {
parent::__construct(/* db info */);
} catch (Exception $e) {
// handle the error
}
}
public function read() {
// read from database
}
public function write() {
// write to database
}
// etc...
}
So your database class will have some simple crud operations. Then your orm can interact with this class like so...
<?php
class ORM {
public function __construct() {
$this->db = new DB();
}
public function find($options) {
return $this->db->read($options);
}
public function save($data) {
return $this->db->create($data); // or update()
}
// etc...
}
This should be enough to get you going. Also, rather than using a singleton pattern for your database, if you don't manage your connections externally, you could use a simple modified registry type pattern (note this isn't a true registry)
<?php
class DB extends PDO {
protected static $instances = array();
public function __construct() ...
public static function get($name) {
if(! isset(self::$instances[$name]) {
self::$instances[$name] = new self();
}
return self::$instances[$name];
}
}
class ORM {
public function __construct() {
$this->db = DB::get('connection1');
}
}
There are better ways to do this but I will leave that up to you.
Related
I am trying out a MVC concept where the main model for a database stems or trees off other models. I wanted to have a main database sort of model which does the connecting and queries. Then, other models are built to support the controller. Ie, a product model can be extended off the main database model to then query rather than using dependency injection.
My current ideology and attempt looks like this for the main database model:
namespace Portfolio\Application;
abstract class DriverModel {
private static $driver;
private $entity;
private function __construct() {
// Connection to the PDO will be done in here
}
private function __clone() {}
public static function getInstance() {
if(self::$driver)
return self::$driver;
self::$driver = new self();
return self::$driver;
}
protected function q($sql, $values = []) {
$stmt = $this->entity->Prepare($sql);
$stmt->execute($values);
return $stmt;
}
}
Then my example profile controller would look something like this (having the methods to use the main database to run queries):
class ProfileModel extends DriverModel {
public function doSomeQ() {
$this->q('SELECT fname FROM users WHERE id = ?', [(int)1]);
}
}
However, When I execute this line of code:
print_r(ProfileModel::getInstance()->doSomeQ());
I am left with this error: (which makes sense.)
Uncaught Error: Cannot instantiate abstract class.
I then remove the abstract attribute from the class (class DriverModel) but now, the instance I am receiving is the instance from the parent class meaning if I do a print_r() on the getInstance() method to the ProfileModel, there is no doSomeQ() method.
Any help on achieving this methodology would be helpful.
You have to use get_called_class() method instead of new self();
http://php.net/manual/en/function.get-called-class.php
Attached you can find sample who show your expected behaviour
class Main {
public static function getInstance() {
$class = get_called_class();
return new $class();
}
}
class Foo extends Main{
}
var_dump(Foo::getInstance()); // Output Foo object
I'm just new to PHP and i cant understand why the code bellow doesn't works.
If i do the same code but not using class things works just fine.
<?php
class DAL
{
public $Conn;
public function __construct()
{
global $Conn;
$Conn = new PDO("mysql:host=localhost;dbname=football", "root","");
$Conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
}
}
class BLL
{
public function GetSeason()
{
$conn = new DAL();
$result = $conn->Conn->query("Select * from season");
print_r($result->fetchAll());
}
}
?>
If I understand right, DAL is Data access layer and BLL is Business logic layer.
Both usually represented not by one class or object, but rather contain objects that represent different levels of abstractions in your application.
Data access layer consists of Data access objects and Business logic layer consists of Business Objects. So you should have one Data access object for each Business Object. In general Data access objects should share one interface (i.e. should extend same Data access object abstract class):
abstract class DataAccessObject
{
protected $conn;
public function __construct($conn)
{
$this->conn = $conn;
}
abstract public function all();
abstract public function get($id);
abstract public function save($object);
abstract public function delete($object);
}
So with your example, the code can look like the following. Here is your season DAO:
final class SeasonDataAccessObject extends DataAccessObject
{
public function all()
{
$query = $this->conn->query('SELECT * FROM `season`');
$seasons = [];
foreach ($query->fetchAll() as $result) {
$seasons[] = $this->hydrate(new Season, $result);
}
return $seasons;
}
public function get($id)
{
// Execute select statement and hydrate result into
// Season Business Object.
// Should return instancs of Season.
}
public function save($season)
{
return null === $season->id
? $this->insert($season)
: $this->update($season);
}
public function delete($season)
{
// Execute delete statement.
}
private function hydrate(Season $season, $result)
{
// Fill $season attributes with values from $result.
}
private function update(Season $season)
{
// Execute update statement.
}
private function insert(Season $season) {
// Execute insert statement.
}
}
And here goes your season Business object:
abstract class BusinessObject
{
private $id;
public function setId($id)
{
$this->id = $id;
return $this;
}
public function getId()
{
return $this->id;
}
}
final class Season extends BusinessObject
{
// Some properties of Season and setters and getters for them.
}
And finally, you can use it all in your program:
$conn = new PDO('mysql:host=localhost;dbname=football', 'root', '');
$conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
$seasonDAO = new SeasonDataAccessObject($conn);
$seasons = $seasonDAO->all();
print_r($seasons);
I guess you got the lingo from "Microsoft Application Architecture Guide" or somewhere else in the Microsoft world (your attributes naming also speaks for it:)). In the modern world, I guess Data access object is Repository and the Business object is Entity.
This is pretty advanced stuff that concerns not even OOP, but Object-oriented design. So you must understand OOP first, because as it was mentioned in the comments, now your code is procedural. Wrapping code in class doesn't make code object-oriented (at the end of the day, this is Object-oriented programming, not Class-oriented programming;))
So, please start with some tutorial on the subject of OOP in PHP (i.e. this one), and gradually you will get better in this.
Done!!!!!
Thank you guys so much!!!
class DAL
{
public $Conn;
public function __construct()
{
$this->Conn = new PDO("mysql:host=localhost;dbname=football",
"root","");
$this->Conn->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
}
}
class BLL
{
public function GetSeason()
{
$conn = new DAL();
$result = $conn->Conn->query("Select * from season");
print_r($result->fetchAll());
}
}
There are many topics about this already, but I have not a clear picture of why factory patterns are better practice than Singleton.
An example
class MySingleton {
public static function numberByWhat( $number ) {
return $number + 100;
}
public static function someCharacters( $string ) {
return $string + 'abc';
}
}
class MyOtherSingleton {
public static function getImage( $url ) {
return '<img src="' . $url . MySingleton::numberByWhat( $50 ) . '">';
}
public static function getTextById( $id ) {
if( $id == 3 ) {
return 'this is my text' . MySingleton::someCharacters( 'Yeah' );
}
}
}
function run() {
echo MyOtherSingleton::getImage( 'http://www.example.com/image.png' );
echo MyOtherSingleton::getTextById( 3 );
}
run();
So there we have 2 classes and a function. When I run() I start a function in the second class. Inside the functions in the second class there are calls to the first class.
How would this look like as a factory pattern?
Why is it better as a factory pattern?
So the examples you've given are neither Singletons nor Factories. What you have here are simply "static classes"--classes with only static methods and properties. Factories and Singletons don't really solve the same problem, either, so it's difficult to compare and contrast them.
Singletons
A Singleton is used to manage shared state or avoid the overhead of instantiating a class multiple times when you only really need "one of something".
Here's an example of a Singleton:
class DatabaseConnection {
// Static reference to the single instance of this class we maintain.
protected static $instance;
// Normal instance properties.
protected $mysql;
// Protected constructor to prevent "new DatabaseConnection();"
protected function __construct() {
$this->mysql = new MySQLConnection("localhost", 3306, "appdb");
}
public static function getInstance() {
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function query($sql) {
return $this->mysql->query($sql);
}
}
Whenever you want to use the DatabaseConnection() in your code, you do it like this:
function getUser($userId) {
$userData = DatabaseConnection::getInstance()->query("SELECT * FROM ...");
}
The DatabaseConnection() is only instantiated once, starting the first time it is used. There will never be more than one created.
Dependency Injection / Inversion of Control
The competing strategy to using a Singleton is, basically, Dependency Injection or Inversion of Control. With Dependency Injection, instead of having one shared, staticly-stored instance of a class, the instance is simply passed from class to class and function to function. Here's a simple example:
class DatabaseConnection {
// Normal instance properties.
protected $mysql;
public function __construct() {
$this->mysql = new MySQLConnection("localhost", 3306, "appdb");
}
public function query($sql) {
return $this->mysql->query($sql);
}
}
class UserManager {
protected $databaseConnection;
public function __construct(DatabaseConnection $databaseConnection) {
$this->databaseConnection = $databaseConnection;
}
public function lookupUser($userId) {
return $this->databaseConnection->query("SELECT ...");
}
}
One advantage of Dependency Injection is that you can test your code much more easily. You could, for example, extend DatabaseConnection and call it TestDatabaseConnection, and make it not actually use a real MySQL database, which can make your tests faster and more reliable. So, the debate is really between Singletons and Dependency Injection / Inversion of Control, not Factories.
Factories
So, now, Factories: Factories simplify the creation of objects, return objects of different classes/subclasses, and help to create objects from "templates". As an example, let's say we have different classes to represent different types of users:
class User {
// ...
}
class ModeratorUser extends User {
// ...
}
class AdminUser extends ModeratorUser {
// ...
}
class GuestUser extends User {
// ...
}
Each of these classes contain methods and properties that would be useful for working with a certain type of user account. So, how would you create and return one of these user objects by User ID, ensuring that the correct type of user is returned? We can use a factory pattern:
class UserFactory {
public static function fromUserId(DatabaseConnection $db, $userId) {
$record = $db->query("SELECT * FROM users WHERE user_id ...");
// ...
switch ($record['type']) {
case 'admin':
return new AdminUser($userId);
break;
case 'moderator':
return new ModeratorUser($userId);
break;
case 'guest':
return new GuestUser($userId);
break;
default:
case 'normal':
return new User($userId);
break;
}
}
}
Then, to load the proper User class, you'd just call:
$user = UserFactory::fromUserId($userId);
If it's an admin account, it will be an AdminUser; if it's a guest account, it will be a GuestUser.
So currently my class DATABASE uses a singleton for a connection and is called in the constructor of my class SQL. I have 4 other classes that extend class SQL for access to its methods. The problem is, the children instantiate each other in some cases so I'm afraid I'm creating multiple class SQL objects because they call their parent constructor by default, aka class SQL. I read about dependency injection, but no clear how to implement it in my situation so this is what I was thinking.
Have all classes extend class DATABASE and make class SQL methods static.
But then I would have to call the singleton connection in class DATABASE, on its own class as so.
class DATABASE {
function __construct() {
self::getInstance();
/// or DATABASE::getInstance ( im not quite positive which way )
}
public static function getInstance() {
if (self::$instance == false) {
self::$instance = new DATABASEMANAGER();
}
return self::$instance;
}
}
I figure this way, since all classes extend class DATABASE, and instantiate each other, I know I am not creating multiple objects.
I hope this makes sense and I can elaborate more if you need me to, but does this make since as an approach to my problem?
I guess you building your class other way around, this approach is more consistent in my opinion.
class DATABASE extends DATABASEMANAGER
{
static $instance;
private function __construct()
{
parent::__construct();
}
public static function getInstance()
{
if (empty(self::$instance))
{
self::$instance = new self();
}
return self::$instance;
}
}
Usage:
class Blog
{
public function __construct()
{
$this->database = DATABASE::getInstance();
}
public function getRecord($id)
{
$result = $this->database->query("SELECT * FROM blog WHERE id='{$id}'");
//or
$result = DATABASE::getInstance()->query("SELECT * FROM blog WHERE id='{$id}'");
//other actions...
}
}
I've been a procedural programmer for over 4 yrs and it's time to start looking into OOP. With that said, let's say I needed to call two methods in my class. Each method requires a connection to the DB so that's two trips to the DB, which also opens multiple connections.
Can this be avoided by having some sort of code in the application layer (constructor?) or does a connection pool have to be setup on the DB side? And just for kicks, I'm not using mysql; I'm using mongodb with codeigniter.
Here's what I have so far, not sure if it's ideal to use?
Here's where I setup my DB info:
database_conn.php
class Database_Conn extends Model {
function _connect() {
$m = new Mongo("localhost:27017", array("persist"=>"x"));
$db = $m->selectDB( "foo" );
return $db;
}
}
sample model file
class Home_model extends Model {
public function __construct() {
// Establish connection to "profiles" table
$this->db_conn = Database_Conn::_connect()->selectCollection( "profiles" );
}
function getMyProfile($username) {
$data = $this->db_conn->findOne(array("username" => $username) );
return $data;
}
function getAll() {
$data = $this->db_conn->find();
return $data;
}
}
you should use singleton pattern
EDIT:
the way you did it, it is possible to call _connect multiple times, which means reconnecting.
singleton implementation usually means you have to make constructor private/protected and define a getInstance method which creates connection on first call and returns the created connection on later calls.
this is what i would do:
class Database_Conn extends Model {
static protected $_instance;
protected $db = null;
final protected function __construct() {
$m = new Mongo("localhost:27017", array("persist"=>"x"));
$this->db = $m->selectDB( "foo" );
}
static public function getInstance() {
if (!(self::$_instance instanceof self)) {
self::$_instance = new self();
}
return self::$_instance;
}
public function getConnection() {
return $this->db;
}
final protected function __clone() { }
}
and then use Database_Conn::getInstance()->getConnection() to get the connection object.
You should look into a manager class for your db connections. Then you can have one central place where you request connections from. If there is already an open connection the manager can return that instead of returning a new connection.
This would be one approach. There are tons of examples out there about how to implement something like this. There already some for mysql and mssql. But you could surely extend for your db.
Use a database layer. Dibi is a great library in this case. http://dibiphp.com