-
Notifications
You must be signed in to change notification settings - Fork 0
Magic methods
#Magic Methods
Well, I figured since PHP has all sorts of magic methods I would go ahead and make some of my own :). Now, they probably aren't 'Magic' as far as lie the php ones are where they get called if there is no matching request, but they are still pretty awesome and get you what you need in a cool way. Pretty much all the 'magic' methods are found in the TableObject class, the class that is responsible for taking results from db queries and building your objects with it. So let's start in there.
##retrieve The first one we come to isn't necessarily a 'magic' method, but it is responsible for an incredible amount of logic, the retrieve method. You can think of this method as the 'getter' method for all of your classes. A simple demo will show you what I mean.
First we start with the class that is going to extend it...
class User extends TableObject {
public $id;
public $first_name;
public $last_name;
public $username;
public $pass_hash;
public static $column_list = array('id', 'first_name', 'last_name', 'username', 'pass_hash');
public static function get_table() {
return 'users';
}
}
As you can see the class contains public members for each column in the database, as well as a public member that is an array of the columns in the database. Now, not all of this is absolutely necessary, the public static member $column_list is not 100% necessary, I just like to include it to save queries on the database and have quicker loading times for my pages. If the member $column_list is not included in the class the base framework will run a query against the database to figure out what columns are necessary when querying it, so by adding this array here we, not only save time and queries on the database, but also we can explicitly exclude columns that are in fact in the users table, like meta data columns that might not be absolutely necessary for day to day operation of the site, so my ultimate recommendation will be to include that in your classes.
Ok, that was a bit of digression there, so let's get back on topic... the retrieve method. Given the above structure getting the user object is extremely simple with the retrieve method, all you need to do is pass it the primary key value when instantiating your class like so,
$user = new User(21); //21 being the value in the id column in the database
See, that was simple. The retrieve method handles the rest of the logic and your variable $user is now the User object full of data from the database. There will be much more on this later in the ARDO documentation, but for now, that serves our purposes.
##build
Let's assume that the info is being passed in a POST array...
$columns = Product::get_columns(); // remember this is only possible if you created the static member $column_list, so another good reason to create it.
$create = array();
/*
* This is just sanitation, if you are sure that only columns are being passed in POST you can omit this part
*/
foreach($_POST as $k => $v) {
if(in_array($k, $columns)) {
$create[$k] = $v;
}
}
$id = Product::build($create);
//logic here...
Super simple. The '//logic here' is just for you to do other things you would desire. At this point the $id variable is either the id of the newly created product in the database, or false if the build failed. The build method is essentially a short cut method, it creates the php object and then calls create() on that object. So the other route to the same end would be...
$columns = Product::get_columns(); //or you could just say Product::$column_list; both work the same
$create = array();
foreach($_POST as $k => $v) {
if(in_array($k, $columns)) {
$create[$k] = $v;
}
}
//Again the above is sanitation and can be omitted if only columns are being passed.
$product = new $product($create);
$id = $product->create();
//more logic
As you can see both methods come to the same end, I just like simplicity and one line of code as shown in the above example is cleaner than 2.
##retrieve_objects Moving right along. Next we would come across the method retrieve_objects. This is a very convenient method that will allow you to build an array of objects that match a certain parameter. So let's say you are building an e-commerce site and there are a ton of categories, each category contains products and so on. Now the user clicks to go into the 'games' category inside the 'PS4' category. Programmatically getting a list of all the things here is extremely simple with this method, let's take a look. Assuming that all the information is coming through post...
$where_clause = " WHERE category = ?";
$params[] = $_POST['category'];
if(isset($_POST['sub_category'])) {
$where_clause .= " AND sub_category = ?";
$params[] = $_POST['sub_category'];
}
$objects = Product::retrieve_objects($where_clause, $params);
Sweet! man that was easy. The $objects variable now contains an array of Product objects whose category is whatever was passed in post, and whose sub_category is what was passed in post, or nothing if nothing was passed in. An even simpler way to do the same thing is to allow it all to be completely dynamic and run this...
$columns = Product::$column_list;
foreach($_POST as $k => $v) {
if(in_array($k, $columns)) {
$keys[] = $k;
$params[] = $v;
}
}
//again that is strictly for sanitation, if only columns in the product class are coming through you can omit it
$where_clause = " WHERE " . implode(' ', array_map(function($key) {
return ' '.$key.' = ? AND';
}, $keys);
$where_clause = substr($where_clause, 0, -3);
$objects = Product::retrieve_objects($where_clause, $params);
Ok, well maybe not simpler, but it is a LOT more dynamic and allows for any possible combination of params. As a side note there is another method called retrieve_object That does the exact same thing, but instead of returning an array of objects, it returns a single object of that type. Of course there is also the retrieve_all_objects method as well, part of the same family and an easy way of getting all objects of that type without writing a where clause.
##get_related Now we come to one of my favorite methods, get_related. This method right here is one of the methods in this framework that makes relationships between objects really really simple for the developer. There is one small standard that needs to be followed when using this, the related item must have a '[PARENT]_id' member. What that means is this... let's say you have a car lot, now that car lot has cars that relate to it right? Well then all you need to do for the relation to work is give your Car class, and cars database, a car_lot_id, assuming that your car lot table is car_lots. So Car->car_lots_id would equal the CarLot id that it belongs to. That's it, an example shall we...
//the parent class
class CarLot extends TableObject {
public $id;
public $name;
public $phone;
public $address;
//... and so on;
public static function get_table() {
return 'car_lot';
}
//... and so on;
}
//The related class...
class Car extends TableObject {
public $id;
public $make;
public $model;
public $cars;
public $car_lot_id; // the one needed for the relationship to work;
//... and so on;
public static $column_list = array('id', 'make', 'model', car_lot_id'); //you get the idea
public static function get_table() {
return 'cars';
}
}
//now the view or controller, or wherever you need the relationship;
$car_lot = new CarLot(2); //remember that will retrieve the car_lot from the db and build the object;
$car_lot->cars = $car_lot->get_related_cars($car_lot->id);
Simple... again, you know it really seems like there is a pattern here, everything is so... so... simple. There is also a static version of the above mentioned method as well, in case you don't want to instantiate your parent class, you would just use this...
$cars = CarLot::get_related_cars(1);
With the '1' being the id of the car lot you want to get the related cars of. I should say that the above mentioned functions also extend to ids as well. Let's say you didn't want to get all of the car objects, you just want to ids of the car objects that relate to the car lot, for reporting or whatever else you can simply tack on _ids to the end of either of those functions up there and you would get back an array of ids that relate to the parent. $car_lot = new CarLot(3); $car_lot->car_ids = $car_lot->get_related_car_ids($car_lot->id); //or the static method $car_ids = CarLot::get_related_car_ids(3); And there you have it. With one simple addition, the {parent}_id column in the database, php related objects are so incredibly simple. If this still isn't simple enough for ya feel free to hop on over to the ARDO page and see how it can be simplified even further with OOF. Oh and a quick side note, these methods do make use of PHPs built in 'overloading' or magic methods, to allow for complete dynamics. Essentially any class that extends TableObject (which should be every model you make) can make use of them.
##retrieve_multiple I guess this should be up near the top since this is pretty much the same as retrieve only it does... well... multiple. Where retrieve is called automatically when you create a new object and pass it an ID or an array of key => value pairs, retrieve_multiple is explicitly called by you when you need to get a bunch of one type of objects and don't really feel like using retrieve_objects, though it is pretty much the same principle, except this doesn't take a string where clause, this takes either an array of ids or an array of conditions so it has a bit more wide range usage. Let's do what we do and go through an example eh?
Let's say you are building a blog website and you have an awesome form that allows users to set certain parameters on the blogs they see, with this method you can pass that data in and get back an array of objects matching those conditions.
//the ajax page that gets the array of data from post from the form
$columns = Blog::$column_list;
$search = array();
foreach($_POST as $k => $v) {
if(in_array($k, $columns)) {
$search[$k] = $v;
}
}
$posts = Blog::retrieve_multiple($search);
There you have it. Mind you the foreach is there just as a safety precaution, if you are sure that only columns in that class can be passed to the page you could do without it. Now at that point $posts will be an array of Blog objects that match the conditions set forth by the submitted, or ajax-ed. Currently it is possible for this to return false if no items where found that match the search criteria. That might change in the future to just return an empty array, but for now, it will either return an array of objects of type static, or false.
##construct_objects_from_rows Last but not least we come to this one... construct_objects_from_rows, I'll bet you can guess what this one does... it takes the results of a sql query, and gives you back objects of type static. Essentially the underlying method of retrieve_objects, the piece that creates the objects before returning it to you. I just figured I would expose these methods, yes these as there is a construct_object_from_row (for single) object creation too. This way you can run a query of your liking and then just push the results through here and out pops shiny new PHP objects. Yep, you guessed it, example time...
Let's say, again, that you are building a blog site and you need to get all the blogs that match a certain param and you only need a couple columns and not all the columns in the table, so you figure instead of querying for everything you'll be all slick and save a little bandwidth and just query the needed columns.
//The ajax called page that receives data via POST
$columns = array_keys($_POST);
$sql = "SELECT ".implode(", ", $columns). " FROM blogs WHERE "; //never hardcode tables, but this is just and example so...
$params = array();
foreach($columns as $column) {
$sql .= " ".$column . " = ? AND";
$params[] = $_POST[$column];
}
$sql = substr($sql, 0, -3);
$results = DB::get()->fetch_all($sql, $params);
$posts = Blog::construct_objects_from_rows($results);
There you have it, $posts now contains an array of Blog objects with the only properties set in the object are the columns that came across in POST. Now of course you can use all the columns and get everything in the objects, I just chose that example because.
Well, that about wraps up this section on the 'magic' methods included in the OOF framework. Feel free to check out the rest of the documentation or just grab it an start building. I think you'll be surprised at just how easy building a site with this really is.