I have recently been working on a project that was thrown upon me at work after another developer left (he was the only one working on it prior to leaving). The project was written in CodeIgniter and uses the MVC framework. While working on the project I noticed something funny or at least something I have not seen before.
After the model is loaded into the controller the object is passed into the view using...
$data['outcomes'] = $this->id_conversion;
With id_conversion being the model that was loaded in at the top of the controller. My question is is this any different then using
new Id_conversion();
in place of the above.
Thanks for any help or anyone able to point me in the correct direction.
Edit. Sorry after reading the comments I see that I need more of my code for this to make sense.
public function person($id)
{
$this->authenticate->check_access(array('admin', 'rps'), 'home');
$this->load->library('page_uri');
$this->load->model('term');
$this->load->model('user');
$this->load->model('id_conversion');
$selected_term = $this->page_uri->get_term();
$current_term = $this->term->current_term_id();
if (!isset($selected_term)) {
$selected_term = $current_term;
}
$term = new Term();
if (!empty($selected_term) && $selected_term !== '0') {
$term = new Term($selected_term);
}
$user = new User($id);
$plans = $user->plans_by_term($term);
$data = array();
$data['user'] = $user;
$data['site_url'] = site_url("reports/person");
$data['current_term'] = $this->term->current_term_id();
$data['selected_term'] = $selected_term;
$data['terms'] = $this->term->sorted_term_list();
$data['term'] = $selected_term;
$data['plans'] = $plans;
$data['outcomes'] = $this->id_conversion;
$this->load->view('template/foundation', $data);
}
the model id_conversion loads in
class Id_conversion extends MY_Model{
function __construct()
{
parent::__construct();
}
/*
* Input a primary or secondary outcome as defined
* in the plan class and
*/
public function id_outcomes($id)
{
$sql = 'SELECT name
FROM outcomes
WHERE id ='. $id;
$query = $this->db->query($sql);
return $query->row_array();
}
}
Using new will create a new object.
Using $this->id_conversion will use the existing object that was already created at some point previously and which was stored in that variable.
Without seeing more of your code, it's utterly impossible to know what state the existing object is in, so I can't tell you what difference it will make to create a new one compared with using the existing one. I would imagine there's a good reason for the program to have already created the object and stored it for you, so I guess it's been set up ready for use, but I can't tell for sure from what you've given us.
But even in the case that the existing object is in an entirely pristine condition and creating a new one would give identical functionality, you'd be wasting system resources in creating an extra object when one already exists. Only a small amount of wastage, to be sure, but it all adds up.
It's probably going to give the same results but not certainly.
If $this->id_conversion is a reference to a model class, that class may have been initialized in a different way. In Codeigniter, you can initialize an instance of a model like this:
$this->load->model('model_name', 'alias_name', $db_params);
If the class Id_conversion doesn't exist and id_conversion is actually an alias, then of course that wouldn't work.
If $db_params are different, then this is much different than just saying new Id_conversion();. Note also that the () are not needed if you aren't passing anything to the constructor. And as mentioned, it creates another unnecessary instance of the class.
And of course, if the state of $this->id_conversion has changed at all, for example:
$this->id_conversion->property = 'value';
...then it will not be the same at all.
Note that $this->id_conversion will be available in the view as well, so while it's probably good practice to explicitly pass it to the view, it isn't strictly necessary. The view runs in the same scope from the controller method that it was called in.
Better to stick to the Codeigniter way unless you are sure you know what you are doing.
Related
The title may be a little vague, but the question is difficult to word properly.
I'm trying to learn PHP OOP (coming from Procedural) and it's a pain - my main stump is selecting from a databased based on a certain value that is usually passed through the URL (at least in procedural).
For example, user.php?ID=2 - then I could quickly define ID using GET and future queries would use that ID.
Since my OOP classes would be in a seperate file to the main page that includes the html and outputs everything, users won't be submitting the ID to that file. In other words, they'll be going to user.php?ID=2 instead of user_c.php?ID=3 which is the class file.
My question is - how do I pass that ID through to the class? I need to select things out of the database based on the profile that they're viewing, but how do I tell the class that?
My apologies for how badly this is worded.
One would do something like this, $data now contains the data returned from the query:
//user_c.php:
Class MyUserClass {
public function getUser($id){
//Query for user data.
return $queryData;
}
}
//user.php
$userClass = new MyUserClass ();
$data = $userClass->getUser($_GET['ID']);
First of all, OOP is not that much different than procedural. The main difference is that instead of data and functions which operate on the data you have objects which encapsulate the data as well as the operations which are valid on that data.
However, in its core, OOP does encapsulate procedural programming, with the difference being that the procedural part happens within objects rather than in the application level.
To migrate from procedural to OOP all you need to do is separate your code in parts which are logically connected, in the case of databases what typically happens is each database table has a class (in MVC frameworks this is called a data model).
For example if you have a table called users you might have a corresponding User class.
class User {
private $id;
private $alsoOtherProperties;
public function __construct($dbconnection, $id) {
//Load the user from id
}
/* Setters and getters and other function here which operate on the user */
}
You then create an instance of a user which you construct from the $id given the database connection. The simplest way is do what you're already doing to get the id. From here on your data will be operating on the User object rather than on a database result. This way you don't have to worry about changing the database structure since you can just update the model to work with the new structure and the rest of the code will not need altering.
For example, say you want to update the "last logged in" column for a user at the time of log in:
//Other code around here
$ID = $db->real_escape_string(strip_tags(stripslashes($_GET['ID'])));
$user = new User($db,ID);
$user->setLastLogin(time());
$user->save();
In this example there's 2 functions defined in the class User in addition to the constructor which is to set the last login time and then update the database row which corresponds to the user. As you can see, this does not have any MySQL specific logic and the underlying code in the user class can update either a MySQL database, a text file, or not do anything (e.g. when just running tests).
Note: This is just an example, probably not a very good one at that, you should really really study OOP to learn more about it.
First and foremost you will need to create a simple database class that will handle your queries.
class DatabaseQuery {
public $parameters;
public $statement;
function __construct($statement,$parameters)
{
global $connection; //this will be your new PDO connection details
$sth = $mysqli->prepare($statement);
$sth ->execute($parameters);
$this -> executedStatement = $sth;
}
function getDetails()
{
$r_result = $this -> executedStatement;
$r_result2 = $r_result->fetch();
$show_result = $r_result2['0'];
return $show_result;
}
function executeStatementOnly()
{
return "Action Successful";
}
function __destruct()
{
//echo "Has been destroyed";
}
}
Next you will pick data from user, you will need to sanitize it using this function
function clean_data($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
Next, pick the data and call your database query class and save or echo the data you are picking.
$get_data = clean_data($_GET["id"]);
$user_details = new DatabaseQuery("SELECT column FROM table WHERE id=?",array($get_data));
echo $user_details->getDetails();
Assuming that until now you did something like this:
// user.php
$id = $_GET['id'];
$myResult = myDbFunction($id);
function myDbFunction($id) {
// do something useful
}
you can re-write this like that:
// user_c.php:
Class MyClass {
public function myDbFunction($id) {
$something = "";
// do something useful
return $something;
}
}
// user.php:
include "user_c.php";
$myClass = new MyClass();
$id = $_GET['id'];
$myResult = $myClass->myDbFunction($id);
And that would produce the same results as if you had placed your class in the same file, like this:
// user.php:
Class MyClass {
public function myDbFunction($id) {
$something = "";
// do something useful
return $something;
}
}
$myClass = new MyClass();
$id = $_GET['id'];
$myResult = $myClass->myDbFunction($id);
I assume you know that one of the main reasons for going OOP over procedural is the re-usability as well as information hiding (i.e. sparing a user of your class the need to understand every detail of it, while still allowing them to use it)
You may want to read up on OOP with PHP, and simply play around with it. While there is a slight differece in the two styles, you should get a hang of it quickly.
Once you make sure you understood the single responsibility principle and follow it, you will surely find that OOP has many advantages over procedural programming.
Sorry if I am not using the best jargon, but I have run into an issue I want to solve early before I write too much code. Which of these options below is "better"? And is there a better way of doing this? Someone mentioned to me abstracting my code but another class seems to be the last thing I need. Also I feel like there's something I can do by potentially making my "get" function seen below into a public static function so that I can use it differently. (its not static right now)
Here is my situation:
I have 2 (relevant to this question) classes, DB (database) and Page (for getting my content to display on my website)
the DB class has a query method that prepares and execute my queries
the DB class also has methods for inserting, getting, deleting things from the database.
I now feel that I may not even need my page class because right on the webpage I can just use those DB methods to call my content. (I store all images, content, page title, description in mysql). Is this not a legitimate way to do this? Won't I need to create a new object each time? such as:
$pg_ID = 2;
$title = new DB($pgID);
$title->get('pages', $pgID, $lang); // 3 tables to pull from for each page
$images = new DB($pgID);
$images->get('images', $pgID, $lang);
$structure = new DB($pgID); // I need these tables mostly because my site is in two languages
$images->get('pages_list', $pgID);
I do not like this potential solution just because to me its counter intuitive. Why should I have to create new objects just to reuse a function? However, what I do right now is something I feel is going to get me some hate mail.
$page = new Page();
$page->find('pages', $pgID, $lang);
$page->lookup($pgID);
$page->retrieve('images', $pgID, $lang);
These are 3 separate functions in my Page class that perform very similar things. Find gets my pages content out of the database and returns it as an object. Lookup does basically the same thing but only needs to pass one variable because its only to do with the html structure of each page regardless of which language is being accessed. retrieve gets all images from a table that get shown in a slider with different language descriptions. But as you can see, all three functions do basically the same thing! They query the database. Thanks for the help with this I am literally just getting into this OOP and its driving me insane. Stack has been very helpful and I think I just didn't know how to search for this to find the answer. Feel free to point me to other questions/answers that I may have missed. It was hard for me to think of the keywords to search for.
we may create other classes indeed, but efficiently so. Maybe we can render DB a public state function. I like the idea of creating a database object, pass it as parameter to an other object, which could then format data with the link he just received:
$pg_ID = 2;
$db = new DB($pg_id);
$page = new Page($db,$pg_ID);
// make sure you assign the parameters a private properties in `Page()` ctor.
then, from inside your function, you can call images, titles and structures at will from $this
$title = $this->DB->get('pages', $this->pgID, $lang);
$images = $this->DB->get('images', $this->pgID, $lang);
$structure = $this->DB->get('pages_list', $this->pgID);
and you can those other method as well
$page->find('pages', $this->pgID, $lang);
$page->lookup($this->pgID);
$page->retrieve('images', $this->pgID, $lang);
Now we do not need to create a new object each time we want information from the database.
Now...
the way I access member functions here $this->pgID is better used by defining a getter: $this->pgID(). I like my getter to have the same name as the property. This might not be a very good idea though.
private function pgID() {
return $this->pgID;
}
As for abstract classes..
I did in fact come very lately into thinking abstract classes were quite cool indeed. I've some problem with wording it, having a constant constructor with custom mandatory functions and possible different implementation of classes seems awesome:
abstract class Page {
function __construct($db,$pgID,$lang,$params='') {
$this->db = $db;
$this->pgID = $pgID;
$this->lang = $lang;
$this->init($params);
}
function pgID() {
return $this->pgID;
}
function lang() {
return $this->lang;
}
abstract function init();
abstract function retrieve();
}
class Structure extends Page {
function init($params) {
// some specific to Structure foo here
}
function retrieve($what='pages_list') {
return $this->db->get($what,$this->pgID,$this->lang);
}
}
class Image extends Page {
function init($params) {
// some specific to Image foo here
}
function retrieve($what='images') {
$images = $this->db->get($what,$this->pgID,$this->lang);
// plus some foo to resize each images
return $images;
}
}
ok, hope you're still there! Now we have a Structure and Image class with requisites constructor arguments, generic functions and a custom retrieve function. We could use them that way:
$db = new DB(2);
$template = new Structure($db,2,'fr');
$template->retrieve();
$slideshow = new Image($db,4,'en');
$slideshow->retrieve();
I do hope you do not have to create a new instance of DB if you use a different page id :-)
jokes appart this helps me using classes in a better structured way, as I might have many different classes to represent different parts of a site, but when called from an index all of them will have the same function names, like retrieve() or print(), list()...
I don't want to get into the weeds on a SPECIFIC implementation for you situation, rather I am going to offer some generic guidance.
First off, you shouldn't have to create a separate database object (dbo) for title, images, or structure. Chances are the DSN used for each dbo you are initializing are the exact same, so I would create a singleton dbo which can be shared across multiple objects. For reference take a look at Doctrine's connection manager.
Secondly, I think your objectification could be implemented better. Following most ORMS implementation, you have a Record class and a Table class. The Record class is a specific instance of a Record in your schema, whereas the Table class executes queries against your store which may result in multiple records. These results are then hydrated into an array (of records).
So what I would suggest is something like this (code has not been tested and some of it has been stubbed for brevity):
class PageTable
{
public static function getById($id)
{
// Validate id, if invalid throw exception
$dbo = Database::getConnection();
$stmt = $dbo->prepare('SELECT * FROM page WHERE id = :id');
$stmt->bindParam(array('id' => $id));
$stmt->execute();
$result = $stmt->fetch();
$page = new Page;
// Hydration
$page->setId($result['id']);
$page->setImages($result['images']);
return $page;
}
}
class Page
{
protected $id;
protected $title;
public function setId($id){}
public function getId(){}
}
Hopefully this separation of Record and methods affecting a single, or multiple records makes sense. You should take a look at a DBAL, like Doctrine.
I am trying to improve the method that I am using to to database transactions in a light framework I've built.
Information to understand the question:
Here's a class I've written (where connect.php loads up database credentials; a wrapper for the PHP PDO, stored in $db; and Base.php):
<?php
require_once('connect.php');
class Advertiser extends Base
{
public static function getByID($id)
{
global $db;
$sql = "SELECT * FROM advertiser WHERE advertiserid=?";
$values = array($id);
$res = $db->qwv($sql, $values);
return Advertiser::wrap($res);
}
public static function add($name)
{
$adv = new Advertiser(null, $name);
$res = $adv->save();
return $res;
}
public static function wrap($advs)
{
$advList = array();
foreach( $advs as $adv )
{
array_push($advList, new Advertiser($adv['advertiserid'], $adv['name']));
}
return Advertiser::sendback($advList);
}
private $advertiserid;
private $name;
public function __construct($advertiserid, $name)
{
$this->advertiserid = $advertiserid;
$this->name = $name;
}
public function __get($var)
{
return $this->$var;
}
public function save()
{
global $db;
if( !isset($this->advertiserid) )
{
$sql = "INSERT INTO advertisers (name) VALUES(?)";
$values = array($this->name);
$db->qwv($sql, $values);
if( $db->stat() )
{
$this->advertiserid = $db->last();
return $this;
}
else
{
return false;
}
}
else
{
$sql = "UPDATE advertisers SET name=? WHERE advertiserid=?";
$values = array ($this->name, $this->advertiserid);
$db->qwv($sql, $values);
return $db->stat();
}
}
}
?>
As you can see, it has fairly standard CRUD functions (Edit: Okay, so only CRU, in this implementation). Sometimes, I'll extend a class like this by adding more functions, which is what these classes are intended for. For example, I might add the following function to this class (assuming I add a column isBanned to the database):
public static function getBanned()
{
global $db;
$sql = "SELECT * FROM advertiser WHERE isBanned=1";
$res = $db->q($sql);
return Advertiser::wrap($res);
}
The question:
How can I create a catchall class that will also load up custom model classes when present and necessary?
For example, if I write the following code:
$model = new Catchall();
$banned = $model->Advertiser::getByID(4);
I would expect my catchall class to modify its queries so that all the references to the tables/columns are whatever name I chose (Advertiser, in this case), but in lower case.
In addition, if I wanted to create a custom function like the one I wrote above, I would expect my catchall class to determine that a file exists in its path (previously defined, of course) with the name that I've specified (Advertisers.php, in this case) and load it.
Advertisers.php would extends Catchall and would contain only my custom function.
In this way, I could have a single Catchall class that would work for all CRUD functions, and be able to easily expand arbitrary classes as necessary.
What are the ideas / concepts that I need to understand to do this?
Where can I find examples of this already in the wild, without digging through a lot of CodeIgniter or Zend sourcecode?
What is what I'm trying to do called?
General Stuff: I would look into Doctrine2 for examples of how they make an ORM in PHP. They use mapping in a markup language to say: this table has these columns of this type. Also, while not in PHP, the Django ORM is very easy to use and understand, and working through that tutorial for 20 minutes or so will really open your eyes to some neat possibilities. (it did for me)
A quick search for "php active record lightweight" returned several interesting examples that might start you down the right path.
PHP Ideas: I would look into the magic getter and setter in php, __GET and __SET that will let you set values on your objects without having to make a getter/setter for each field of each table. You could make a single __SET that will make sure that set field is a field in that table, and add it to the list of "fields to update" next time that object is saved. BUT, this is not really a good idea long term, as it gets out of hand quickly, and is brittle.
Advice: Lastly, I worked at a company that used a system that looks almost exactly like this, and I can say unequivocally, you do not want to try to scale this long term. A system like this (the active record pattern) can save massive amounts of time up front, by not having to write queries and things, but can cost tons down the road, if you ever want to start unit testing business logic on the object classes.
For example, it is not possible to mock/dependency inject that static GetById method (it is basically a global method), so every time that is called in code, the code will go to the real database and return a real object. It doesn't take much coding like this to make a system that is almost impossible to test, snarled and tightly coupled to the database.
While they can perform a little slower than your code above, if you are planning on having this around for a considerable amount of time, try looking into ORM tools.
Edit It's called Active Record.
There are a couple different design patterns for what you are trying to do. Look into Data Mapper and Active Record.
Using PHP's "magic method" __get, you can produce this functionality, when you access it via :
$model = new Catchall();
$banned = $model->Advertiser->getByID(4);
... it will a) check to see if the class Advertiser is already defined, b) check for a file called Advertiser.php and include it, or c) return a new instance of a generic class.
The syntax you used in your example with :: assumes that the returned class is static. I have not written this code to contend with that, but it should be trivial to do so.
See the docs: http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
Quick and dirty example:
public function __get($name) {
$instance = false;
// see if there is already a class with the requested name
if (class_exists($name)) {
$instance = new $name();
}
// check to see if there is an object def for the requested object
if ($instance === false && file_exists(PATH_TO_OBJECTS.$name.'.php')) {
require_once(PATH_TO_OBJECTS.$name.'.php');
$instance = new $name();
}
// if instace is still not found, load up a generic
if ($instance === false)
$instance = new Catchall($name);
return $instance;
}
In OOP, sometimes you see something similar to this:
$memberID = $system->members->memberID();
I was wondering and totally confused on the part where it is ->members->... How does that work?
For example, lets say I have a class that I call up called $systems, then how can I put ->members-> after it to run the members class?
I only know how to do something along the lines of this:
$system = new system();
$memberID = $system->memberID();
But I would like to know how to do this:
$system = new system();
$memberID = $system->members->memberID();
Thanks!
-- UPDATE --
Here's a little update, thanks to everyone who helped me out this far! You guys really pointed me in the right direction, I actually have a great answer to my own question! :) And thanks to the moderator who edited this question, I'm sorry I wasn't familiar with the bbcode syntax.
I wanted something to automatically make the new classes, for example calling ->members-> would be automatically included using __get() rather then having to do manually put in something like "new members()". A little difficult for me to explain, but I hope you got the basics of it.
Anyhow, here is the code that I use:
<? class system {
public function __get($name){
$file = 'lib/'.$name;
if(file_exists($file)){
require_once($file);
$classname = $name;
$this->$name = new $classname($this);
return $this->$name;
}else{
die('Class '.$name.' could not be loaded (tried to load class-file '.$file.')');
}
}
} ?>
Now, if I were to do something the lines of this:
$system = new system();
$system->members->functionHere();
It would automatically create a new instance of the members class and require the file from the lib folder.
If this is against the rules then I apologize. I just wanted to post this for anyone who came across this question while searching Google, because I know I always land up here when googling things!
the $system variable holds an object which has a property named $members which itself holds an object which has a property $memberID
$system = new system();
$system->members = new Members(); // or whatever it must be
$system->members->memberId();
When you see something like that, you know that someone has most probably done something wrong!
In order for this code to work, you need to grant public access to a member variable of an object (the former storing an object).
To grant public access to such a member variable is in most cases bad practice. The variable should only be accessible through a getter (at least, it will still violate the LoD).
This code breaks the principle of encapsulation and the LoD (Law of Demeter).
[EDIT]
Why it is almost certainly a mistake:
A) Granting direct public access to member variables is in most cases a mistake, because it makes the public interface of your class rigid (hard to change). If you have a getter, you can change the implementation of the member anytime, the getter will still be the same and you don't need to change the call from anywhere. You can NEVER write a proxy for direct access to a variable! Writing a proxy for a getter on the other hand is easy!
B) Granting direct public access to member variables is in most cases a mistake, because you let everyone talk to a class inside a class directly! This will most probably lead to higher maintainance costs when the public interface of any of these two classes changes.
[/EDIT]
members is object property of system and is also an object that contains method memberID().
To assign property to your object, simply do something like this:
class System {
function __construct() {
$this->members = new Members();
}
// etc
}
or
$systemObj = new System();
$systemObj->members = new Members();
It really really depends on the context you wish to use :)
As #markus mentioned, properties must be declared public if you're accessing them from outside. Also, using setters/getters is often much better ...
So my current understanding of classes are:
Singleton for a class that will only ever be instantiated once.
Static for a class that doesn't get instantiated but just exists.
Regular? For a class that can get instantiated over and over.
So I'm doing a small open source project and as for dealing with users, I thought of how I could deal with it, for example:
Creating a user - I could instantiate a users object and then call a method create on it. Or I could have a singleton so the users object always exists and call create on that?
I just think it seems sort of sloppy to create an object for each user related action, like updating a users credentials, would I want to instantiate another user object and then call a method update on it?
Just confused about how to actually apply OOP, and the best way to do.
Thanks for any/all help you guys can provide.
Even if it's a small project I'd recommend looking at the available PHP frameworks. CodeIgniter leaves a small footprint and embraces fast deployment.
For this case, if we leave out the possible usage of frameworks I'd go with a User class that would look something like this:
class User{
private $user = array();
public function __construct($user_id = 0){
if($user_id !== 0){
$this->user = $this->get($user_id);
}
}
public function get($user_id){
// .. code
}
public function update($data, $user_id = 0){
if($user_id == 0){
$user_id = $this->user['user_id'];
}
// .. code
}
public function create($data){
// .. code
}
public function delete($user_id){
// .. code
}
}