I have the following classes:
namespace database;
class database {
protected $table = '';
function __construct()
{ // Stuff here }
public function all() {
// Load from database
// Return array with results
}
}
class tbl_organisation_types extends database {
protected $table = 'tbl_organisation_types';
function __construct($data = [])
{
parent::__construct();
// do stuff with $data
}
}
I fetch all rows from the database, iterate through them and create new objects. Since other classes extend this database class, the generated objects have to be dynamic.
When i try to generate the objects dynamically like this
$return[] = new $this->table($row);
I get the following error
Uncaught Error: Class 'tbl_organisation_types' not found in /path/to/tbl_organisation_types.php
If I generate the objects with a fixed classname like this it works. But then it wouldn't work for multiple classes.
$return[] = new tbl_organisation_types($row);
Is there a way to dynamically generate objects and/or why is mine not working?
Using PHP 7.1
I am getting an impression, that you are attempting to create something like active record there. I would advise against that.
As for why your class is not working, you probably should do something like:
$name = '\\database\\' . $this->table;
$instance = new $name($row);
When you use a string to initialize class, it has to contain the fully qualified class name, no matter in which namespace your code is. And same applies even to aliases.
Related
i try work with the a class of database, and connect it to wipe it I build using extends, but I get an error. Example:
class Admin extends Sdba{
// Var:
public $login = false;
public $users;
public $users_list;
// Function:
public function UserLogin($char) {
if($this->login) {
print "in";
}else{
$this->users = Sdba::table('users'); // creating table object
$this->users_list = $this->users->get();
print_r($this->user_list);
print "out";
}
}
}
and my DB class is:
http://foska.pp.ua/codecanyon/sdba/
my error is: Fatal error: Call to private Sdba::__construct() from invalid context
Tanks !!
You are inheriting from Sdba class, and when you do that, the actual method: Sdba::table can be referenced as self::table in your child class.
Therefore, the code for creating table object should use:
$this->users = self::table('users'); // creating table object
You can also use parent::table to reference your function. But, the benefit of using self over parent is that you can further modify your table method in this child class, if need arises.
it should use parent::table because you use table method from extended class
$this->users = parent::table('users'); // creating table object
I thought about using an actual ORM like Doctrine, then I figured its download link was even broken...and all tutorials online dated back to 2011. Also I'll have to write yaml files.
Then I start off by trying to write my own model class in ORM style.
I just fill it up with fields and save it to database, which is easy.
But I encounter a problem trying to retrieve data from database.
class User extends CI_Model {
public $id;
public $email;
public $displayName;
public function save() {
.....
}
public function search_by_email($email) {
$user = new User();
$this->db->select('email')->from('user')->where('email', $email);
$result = $this->db->get();
if ($result->num_rows()==0) {
return false;
}else {
foreach ($result->result() as $field) {
}
}
}
I know normally in CodeIgniter, you return $query->result(), well as ORM custom, I'm trying to return an object...Is there a way to do this? What function should I use?
result takes a string that represents a class that it will instantiate and assigned the result data (each field as a property of the object):
$query = $this->db->query("SELECT * FROM users;");
foreach ($query->result('User') as $row)
{
echo $row->name; // call attributes
echo $row->reverse_name(); // or methods defined on the 'User' class
}
regarding your comment, i'm pretty sure that codeigniter has no idea about anything regarding the class you pass to the result method. It looks like it just instantiates it and sets property and valuefor each column/value returned from the db:
$this->custom_result_object[$class_name][$i] = new $class_name();
foreach ($this->{$_data}[$i] as $key => $value)
{
$this->custom_result_object[$class_name][$i]->$key = $value;
}
One ORM that works quite well with codeIgniter is php-activerecord which is based off the rails active record model.
The function your trying to copy "search_by_email" is done through a
Late static binding method.
So you might see functions that are called like so:
Object::find_by_email()
Object::search_by_email()
This is my problem, I have a tiny PHP MVC framework i built.
Now when Im in Controller, i should be able to load a Model.
I have Models named like database tables like Users.php, Pages.php etc.
All Controllers extend BaseController, and all Models extend BaseModel, this way I can have some methods available to all Controllers. Like from any Controller I can use loadModel method like this:
$usersModel = $this->loadModel("Users");
Now $usersModel will be object that represents users database table, and from there I should open database connection, and fetch, update, delete stuff from users table.
To get database connection from my Models, baseModel has method loadDatabase() and I use it like this:
$database = $this->loadDatabase();
This would return class that is thin layer around PDO so from there I can use something like this:
$data = $database->fetchAssoc("SELECT * FROM users WHERE name = ?", array("someone"));
This is how I would return some $data from Model to the Controller.
So basicly, Controller can load a model, and then call methods on that model that would return some data or update or delete etc.
Now, Controller can load more then one model. And each model should load database, and this is where it gets complicated. I need only one connection to the database.
This is how loadDatabase method looks:
public function loadDatabase()
{
// Get database configuration
require_once("Application/Config/Database.php");
// Build configuration the way Database Object expects it
$dns = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
$username = $db_config['db_user'];
$password = $db_config['db_pass'];
$options = $db_config['db_options'];
// Return new Database object
return new \Core\Database\Database($dns, $username, $password, $options);
}
So before I load a Database object, i must load configuration for database connection, as Database objects __constructor expects it. Then I instanciate new database object and return it.
Now Im stuck and I dont know is this the right way to loadDatabase from model?
How should I set this up, how should I load database from inside the model so there is always only one instance of database object. Beacuse if I do something like this from Controller:
$users = $this->loadModel("Users");
$pages = $this->loadModel("Pages");
$users->doSomethingThatNeedsDatabase();
$users->doSomethingThatNeedsDatabase();
$pages->doSomethingThatNeedsDatabase();
I would create 3 database objects :(
So my question is, how should I load Database from inside the Models, and how should that method look in BaseModel?
What if I would like to use 2 databases, I will have some big problems with this setup.
How can I achive this without using singleton pattern?
At the moment, I also have something like this:
public function getDatabase()
{
$reg = \Core\Registry\Registry::getInstance();
$db = $reg->getObject("database");
if(!isset($db))
{
require_once("Application/Config/Database.php");
$dns = "{$db_config['db_driver']}:host={$db_config['db_host']};dbname={$db_config['db_name']}";
$username = $db_config['db_user'];
$password = $db_config['db_pass'];
$options = $db_config['db_options'];
$db = new \Core\Database\Database($dns, $username, $password, $options);
$reg->setObject('database', $db);
}
return $reg->getObject('database');
}
This is Registry pattern, where I could hold shared objects. So when Model asks for DB connection I could check if DB Class is in Registry, and return it, if not I would instaciate and then return... The most confusing thing is that I need to load configuration array...
So what is the best way, to load Database from Models?
Thanks for reading, this was a very long question, but this is bothering me so much, i hope someone could help me with this one... Thanks!
You are going in the wrong way about solving this.
Instead of each time manually making a new "Model" and then configuring it, you should create a structure that does it for you ( extremely simplified version ):
class ModelFactory
{
protected $connection = null;
// --- snip --
public function __construct( $connection )
{
$this->connection = $connection;
}
// --- snip --
public function buildMapper( $name )
{
$instance = new {$name}( $this->connection );
return $instance;
}
// --- snip --
}
This class you would be using in index.php or bootstrap.php , or any other file you use as entry point for your application:
// at the bootstrap level
$modelFactory = new ModelFactory( new PDO(...) );
// i am assuming that you could get $controllerName
// and $action from routing mechanism
$controller = new {$controllerName}( $modelFactory );
$controller->{$action}();
The main problem you have is actually cause by misunderstanding what Model is. In a proper MVC the Model is a layer, and not a specific class. Model layer is composed from multitude of class/instances with two major responsibilities:
domain business logic
data access and storage
The instances in first group are usually called Domain Objects or Business Objects (kinda like situation with geeks and nerds). They deal with validations, computation, different conditions, but have no clue how and where information is stored. It does not change how you make an Invoice , whether data comes from SQL, remote REST API or a screenshot of MS Word document.
Other group consists mostly of Data Mappers. They store and retrieve information from Domain Objects. This is usually where your SQL would be. But mappers do not always map directly to DB schema. In a classic many-to-many structure you might have either 1 or 2 or 3 mappers servicing the storage. Mappers usually one per each Domain Object .. but even that is not mandatory.
In a controller it would all look something like this.
public function actionFooBar()
{
$mapper = $this->modelFactory->buildMapper( 'Book' );
$book = $this->modelFactory->buildObject( 'Book' );
$patron = $this->modelFactory->buildObject( 'Patron' );
$book->setTitle('Neuromancer');
$mapper->fetch( $book );
$patron->setId( $_GET['uid']);
if ( $book->isAvailable() )
{
$book->lendTo( $user );
}
$mapper->store( $book );
}
Maybe this will give you some indications for the direction in which to take it.
Some additional video materials:
Advanced OO Patterns (slides)
Global State and Singletons
Don't Look For Things!
Best way for these models to use dependency injection pattern.
public function loadModel() {
$db = $this->loadDatabase();
$model = new Model();
$model->setDatabase($db);
return $model;
}
where loadDatabase() should once init and after return simple instance of database connection.
Try this:
class Registry
{
/** #return Registry */
public static function getInstance() {}
public function getObject($key) {}
public function setObject($key, $value) {}
/** #return bool */
public function isObjectExists($key) {}
}
class Db
{
const DB_ONE = 'db_one';
const DB_TWO = 'db_two';
protected static $_config = array(
self::DB_ONE => array(),
self::DB_TWO => array(),
);
public static function getConnection($dbName) {}
}
abstract class BaseModel
{
abstract protected function _getDbName();
protected function _getConnection()
{
$dbName = $this->_getDbName();
if (!Registry::getInstance()->isObjectExists($dbName)) {
Registry::getInstance()->setObject($dbName, Db::getConnection($dbName));
}
return Registry::getInstance()->getObject($dbName);
}
}
class UserModel extends BaseModel
{
protected function _getDbName()
{
return Db::DB_ONE;
}
}
class PostModel extends BaseModel
{
protected function _getDbName()
{
return Db::DB_TWO;
}
}
Good luck!
I have the following PHP Classes
class.property.php
class.location.php
class.amenity.php
class.category.php
all four classes handles the respective CRUD operations for different categories. i want to refactor my codes and hence wants to go with the Parent Child Structure.
for example i used to initialize classes on every page like this.
$property = new Property($dbh);
$location = new Location($dbh);
$category = new Category($dbh);
$amenity = new Amenity($dbh);
and then i used to access class methods and properties individually like
$property->user;
$property->contact;
$property->save();
$location->countries();
$location-states();
Andso on, every class is executing indivdually, instead of accessing it like this i would like to use it this way.
$property = new Property($dbh)
above should be the Parent class and rest three child class, and so i should be able to access all class methods and properties only through parent class for example i should only be able to access it like this..
$property->location->countries();
$property->locations->states();
$property->location->countryId;
$property->amenity->name;
$property->amenity->save();
and so on..
i tried to figure out how to do it and came out with this solution.
class Property{
public $amenity;
public function __construct() {
require_once('class.amenity.php');
$this->amenity = new Amenity;
}
}
class Amenity {
public function create($test) {
return $test;
}
}
now if i want to access the create() method in Amenity class i simply call
$property->amenity->create()
and it works, however i would like to know if this is the correct method of implementing the Parent Child Structure or am i missing something?
There is no need for the create() call:
class Property{
public $amenity;
public function __construct() {
require_once('class.amenity.php');
$this->amenity = new Amenity;
}
}
class Amenity {
}
$property = new Property;
$amenity = $property->amenity;
At the very most, you'll want to make the properties protected, and use getters and setters.
Ok this is not just a PHP question, but I have this problem in PHP so I will post the example in PHP.
Example:
I have three classes, say, data_abstract, person, and student. Now, I have one array of data related to each of those objects.
class person extends data_abstract
{
protected $data; //name, gender, etc
}
class student extends person
{
protected $data; //student_id, etc
}
Now, assuming each of those "data" property is from database tables, for example, table_person, table_student.
Upon instantiation, we will parse the class name by get_class() function, and get data from their related tables.
class data_abstract
{
public function __construct()
{
$name = get_class($this);
$table = 'table_' . $name;
$this->data = DB->query('SELECT * FROM ' . $table);
//whatever DB constant is,
//I'm just trying to get all rows of data from the related table.
}
}
Ok, now the problem, when I instantiate student by $student = new student(); the constructor will get data from table_student for me and put it in $student->data, but I won't be able to get the data from table_person and put those two sets of data into one object.
By extending another class, we can have all the methods (functions) extended and customized (via polymorphism), but extending the attributes/properties of each level of object seems to be hard, at least without some manual construction.
Is there any way in the abstraction level to achieve this?
(thanks for reading, wish I could've made the question clearer.)
If I understand well :
you want all your DB data in $data;
$data must be feed with data from the table 'table_classname';
$data "inherit" from $data that should have been loaded in parents class with that process.
In that case, you should externalize $data feeding so you can overload the data feeding. I edited, now we have a working example :
class DataAbstract // Using caps is much better for class name
{
public function __construct()
{
$this->loadData();
}
public function loadData()
{
// don't use getclass on $this or $this will refer to the children
$table = 'table_' . __CLASS__;
$this->data = array($table);
}
}
class Person extends DataAbstract
{
public function __construct()
{
parent::__construct();
}
public function loadData()
{
parent::loadData();
$table = 'table_' . __CLASS__;
$this->data = array_merge($this->data, array($table));
}
}
class Student extends Person
{
public function __construct()
{
parent::__construct();
}
public function loadData()
{
parent::loadData();
$table = 'table_' . __CLASS__;
$this->data = array_merge($this->data, array($table));
}
}
$c = new student();
print_r($c->data);
Outputs
Array
(
[0] => table_DataAbstract
[1] => table_Person
[2] => table_Student
)
BTW, remember that PHP got introspection, it allows you you to set the fields you need dynamically : maybe cleaner that using a big Array.
Provided you know all the fields names, you can do something like
function populate($data) // get the array from the DB
{
$fieldList = get_class_vars($this); // get the filed list
foreach ($fieldList as $key => $value)
{
$this->$key = $data[$key]; // feed the field one by one with the array
}
}
Personally, I would put the database loading class in an protected method that takes the attribute $tablename, and which loads all the data. Then in the constructor of the class call it by hand, and the parent.
class Person
{
public function __construct() {
$this - > loadData("Person");
}
}
Class Student extends Person
{
public function __construct() {
parent::__construct();
$this - > loadData("Student");
}
}
Now, when you construct Student both data from Student and Person is loaded. if you use array_merge() the 2 data arrays will be merged into one.
It's a matter of style; some people would critisise this by saying that you are now repeating something twice - more work to refactor - but I would say you are decoupling the class names and interfaces from the database design (a good thing) and with the parent call, the code is now more OO.