First things first. I may be completely off track with this. I'm still learning with Mongo and NOSql solutions in general. We have a new component to our app we are writing and instead of sitting down and messing with a relation database we wanted to use something that would fit better with our objects.
So let's take a simple example:
Class User extends \Model {
public $name;
public $hobbies;
}
$name would just be a string. But lets say $hobbies is an object or an array of objects. I want to just be able to throw this into a data store and be able to retrieve it later.
At first I went down the road of breaking the object down into an array and storing that in Mongo and then pulling it back out and populating an object. Pretty simple with a generic import and export method I made. The problem comes when I have some robust objects that have other objects as member variables and so on. At that point I could still export into a multidimensional array and store it fine. But importing back into the objects became problematic.
The other option I could do is just seralize() the object and store that in mongo along with some descriptive data.
Sooooo. Thoughts?
Part of my problem here is that I'm new to the NOSql products and not sure their full limitations/potential. Am I just looking at Mongo wrong and trying to make it do something it's not meant to do? I'd prefer not to use some 3rd party module and would rather write something simple and lightweight.
Although I didn't want to use a 3rd party app, Doctrine's ODM for Mongo seems to do exactly what I wanted. Got it set up and seems to be working good so far.
http://www.doctrine-project.org/projects/mongodb-odm.html
I think serialize is the way to go here. Then you can use the magic methods __sleep and __wakeup for each class to handle any tricky situations.
The other option here to serialize your objects into arrays instead of just using "serialize". If I'm not mistaken, you can actually override the "serialize" method in these sub-objects and basically have them serialize themselves into arrays (or more specifically hash-tables).
If Doctrine does this for you, then all the better. But if you just want this feature you can probably cook your own.
Related
Intoduction problem:
What is the best practice to build my class T object, when I receive it from a MongoCursor::getNext()? As far as it goes, getNext() function of a MongoCursor returns with an array. I wish to use the result from that point as an object of type T.
Should I write my own constructor for type T, that accepts an array? Is there any generic solution to this, for example when type T extends G, and G does the job as a regular way, recursively (for nested documents).
I'm new to MongoDB, and I'd like to build my own generic mapper with a nice interface.
Bounty:
Which are the possible approaches, patterns and which would fit the concept of MongoDB the most from the view of PHP.
This answer has been rewritten.
Most data mappers work by representing one object per class or "model" is normally the coined term. If you wish to allow multiple accession through a single object (i.e. $model->find()) it is normally demmed so that the method will not actually return an instance of itself but instead that of an array or a MongoCursor eager loading classes into the space.
Such a paradigm is normally connected with "Active Record". This is the method that ORMs, ODMs and frameworks all use to communicate to databases in one way or another, not only for MongoDB but also for SQL and any other databases to happen to crop up (Cassandra, CouchDB etc etc).
It should be noted immediately that even though active record gives a lot of power it should not be blanketed across the entire application. There are times where using the driver directly would be more benefical. Most ORMs, ODMs and frameworks provide the ability to quickly and effortlessly access the driver directly for this reason.
There is, as many would say, no light weight data mapper. If you are going to map your returned data to classes then it will consume resources, end of. The benefit of doing this is the power you receive when manipulating your objects.
Active record is really good at being able to provide events and triggers from within PHP. A good example is that of an ORM I made for Yii: https://github.com/Sammaye/MongoYii it can provide hooks for:
afterConstruct
beforeFind
afterFind
beforeValidate
afterValidate
beforeSave
afterSave
It should be noted that when it comes to events like beforeSave and afterSave MongoDB does not possess triggers ( https://jira.mongodb.org/browse/SERVER-124 ) so it makes sense that the application should handle this. On top of the obvious reason for the application to handle this it also makes much better handling of the save functions by being able to call your native PHP functions to manipulate every document saved prior to touching the database.
Most data mappers work by using PHP own class CRUD to represent theirs too. For example to create a new record:
$d=new User();
$d->username='sammaye';
$d->save();
This is quite a good approach since you create a "new" ( https://github.com/Sammaye/MongoYii/blob/master/EMongoDocument.php#L46 shows how I prepare for a new record in MongoYii ) class to make a "new" record. It kind of fits quite nicely semantically.
Update functions are normally accessed through read functions, you cannot update a model you don't know the existane of. This brings us onto the next step of populating models.
To handle populating a model different ORMs, ODMs and frameworks commit to different methods. For example, my MongoYii extension uses a factory method called model in each class to bring back a new instance of itself so I can call th dynamic find and findOne and other such methods.
Some ORMs, ODMs and frameworks provide the read functions as direct static functions making them into factory methods themselves whereas some use the singleton pattern, however, I chose not to ( https://stackoverflow.com/a/4596323/383478 ).
Most, if not all, implement some form of the cursor. This is used to return multiples of the models and directly wraps (normally) the MongoCursor to replace the current() method with returning a pre-populate model.
For example calling:
User::model()->find();
Would return a EMongoCursor (in MongoYii) which would then sotre the fact that the class User was used to instantiate the cursor and when called like:
foreach(User::model() as $k=>$v){
var_dump($v);
}
Would call the current() method here: https://github.com/Sammaye/MongoYii/blob/master/EMongoCursor.php#L102 returning a new single instance of the model.
There are some ORMs, ODMs and frameworks which implement eager array loading. This means they will just load the whole result straight into your RAM as an array of models. I personally do not like this approach, it is wasteful and also does not bode well when you need to use active record for larger updates due to adding some new functionality in places that needs adding to old records.
One last topic before I move on is the schemaless nature of MongoDB. The problem with using PHP classes with MongoDB is that you want all the functionality of PHP but with the variable nature of MongoDB. This is easy to over come in SQL since it has a pre-defined schema, you just query for it and jobs done; however, MongoDB has no such thing.
This does make schema handling in MongoDB quite hazardous. Most ORMs, ODMs and frameworks demand that you pre-define the schema in the spot (i.e. Doctrine 2) using private variables with get and set methods. In MongoYii, to make my life easy and elegant, I decided to retain MongoDBs schemaless nature by using magics that would detect ( https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L26 is my __get and https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L47 is my __set ), if the property wa inaccessible in the class, if the field was in a internal _attributes array and if not then just return null. Likewise, for setting an attribute I would just set in the intrernal _attributes variable.
As for dealing with how to assign this schema I left internal assignment upto the user however, to deal with setting properties from forms etc I used the validation rules ( https://github.com/Sammaye/MongoYii/blob/master/EMongoModel.php#L236 ) calling a function called getSafeAttributeNames() which would return a list of attributes which had validation rules against them. If they did not have validation rules then those attributes which existed in the incoming $_POST or $_GET array would not be set. So this provided the ability for a schema, yet secure, model structure.
So we have covered how to actually use the root document you also ask how to data mappers handle subdocuments. Doctrine 2 and many others provide full class based subdocuments ( http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/embedded-mapping.html ) but this can be extremely resourceful. Instead I decided that I would provide helper functions which would allow for flexible usage of subdocument without eager loading them into models and so consuming RAM. Basically what I did was to leave them as they are a provide a validator ( https://github.com/Sammaye/MongoYii/blob/master/validators/ESubdocumentValidator.php ) for validating inside of them. Of course the validator is self spawning so if you had a rule in the validator that used the validator again to issue a validation of a nested subdocument then it would work.
So I think that completes a very basic discussion of ORMs, ODMs and frameworks use data mappers. Of course I could probably write an entire essay on this but this is a good enough discussion for the minute I believe.
I am wondering on the best way to go about creating a list of objects.
Currently, i have a class that deals with orders. In order to retrieve an order it needs to call to an API we were provided with. The API calls are VERY expensive to the point that i could make a call that returns 5000 orders faster than i could make 2 separate calls for 2 separate orders.
Because of this, i built my class to be initialized 2 ways, one way allows me to pass an order number and it initializes itself, but if i pass it an array, it uses the data from the array to create the object.
Now i have functions like GetOrderList($startDate, $endDate) that make one call to the API and fill an array full of Order objects that get returned so i can do stuff with them.
This feels 'hacky' to me, so i was wondering if there was an accepted way of doing what i am trying to accomplish while being more OOP.
Note: this is for a personal project that i am using to learn best practices so i would rather hear what i 'should have done' vs 'what i can do from here'
It sounds fine to me in the case. If you want to be "more correct" (which you can ALWAYS be), then you might want to make a OrderManager object which has a class method to manage collections of Orders. An example call might look like this:
<?php
class OrderManager {
public static function getListByDateRange($startDate, $endDate) {
// ...
return $listOfOrders;
}
}
$orderList = OrderManager::getListByDateRange($startDate, $endDate);
?>
This is called the mediator pattern. It gives the flexibility of extending the manager class to have other forms of querying later or if you find yourself doing this a lot, you can make a generic manager class and just specify which types of objects it'll work with in the subclass.
There are pretty much two ways of doing it. There's the way you're doing it, which by the sounds of what you said, you're basically creating an array (list) of objects. The OOP way would be to create a "container" class (probably by extending ArrayObject or using SplFixedArray) that holds all of the objects. Then you could attach an iterator (probably RecursiveArrayIterator) that would loop through all of your stored objects and apply whatever functionality you require.
Now that I have read an awfull lot of posts, articles, questions and answers on OOP, MVC and design patterns, I still have questions on what is the best way to build what i want to build.
My little framework is build in an MVC fashion. It uses smarty as the viewer and I have a class set up as the controller that is called from the url.
Now where I think I get lost is in the model part. I might be mixing models and classes/objects to much (or to little).
Anyway an example. When the aim is to get a list of users that reside in my database:
the application is called by e.g. "users/list" The controller then runs the function list, that opens an instance of a class "user" and requests that class to retrieve a list from the table. once returned to the controller, the controller pushes it to the viewer by assigning the result set (an array) to the template and setting the template.
The user would then click on a line in the table that would tell the controler to start "user/edit" for example - which would in return create a form and fill that with the user data for me to edit.
so far so good.
right now i have all of that combined in one user class - so that class would have a function create, getMeAListOfUsers, update etc and properties like hairType and noseSize.
But proper oop design would want me to seperate "user" (with properties like, login name, big nose, curly hair) from "getme a list of users" what would feel more like a "user manager class".
If I would implement a user manager class, how should that look like then? should it be an object (can't really compare it to a real world thing) or should it be an class with just public functions so that it more or less looks like a set of functions.
Should it return an array of found records (like: array([0]=>array("firstname"=>"dirk", "lastname"=>"diggler")) or should it return an array of objects.
All of that is still a bit confusing to me, and I wonder if anyone can give me a little insight on how to do approach this the best way.
The level of abstraction you need for your processing and data (Business Logic) depends on your needs. For example for an application with Transaction Scripts (which probably is the case with your design), the class you describe that fetches and updates the data from the database sounds valid to me.
You can generalize things a bit more by using a Table Data Gateway, Row Data Gateway or Active Record even.
If you get the feeling that you then duplicate a lot of code in your transaction scripts, you might want to create your own Domain Model with a Data Mapper. However, I would not just blindly do this from the beginning because this needs much more code to get started. Also it's not wise to write a Data Mapper on your own but to use an existing component for that. Doctrine is such a component in PHP.
Another existing ORM (Object Relational Mapper) component is Propel which provides Active Records.
If you're just looking for a quick way to query your database, you might find NotORM inspiring.
You can find the Patterns listed in italics in
http://martinfowler.com/eaaCatalog/index.html
which lists all patterns in the book Patterns of Enterprise Application Architecture.
I'm not an expert at this but have recently done pretty much exactly the same thing. The way I set it up is that I have one class for several rows (Users) and one class for one row (User). The "several rows class" is basically just a collection of (static) functions and they are used to retrieve row(s) from a table, like so:
$fiveLatestUsers = Users::getByDate(5);
And that returns an array of User objects. Each User object then has methods for retrieving the fields in the table (like $user->getUsername() or $user->getEmail() etc). I used to just return an associative array but then you run into occasions where you want to modify the data before it is returned and that's where having a class with methods for each field makes a lot of sense.
Edit: The User object also have methods for updating and deleting the current row;
$user->setUsername('Gandalf');
$user->save();
$user->delete();
Another alternative to Doctrine and Propel is PHP Activerecords.
Doctrine and Propel are really mighty beasts. If you are doing a smaller project, I think you are better off with something lighter.
Also, when talking about third-party solutions there are a lot of MVC frameworks for PHP like: Kohana, Codeigniter, CakePHP, Zend (of course)...
All of them have their own ORM implementations, usually lighter alternatives.
For Kohana framework there is also Auto modeler which is supposedly very lightweight.
Personally I'm using Doctrine, but its a huge project. If I was doing something smaller I'd sooner go with a lighter alternative.
I'm new to using an MVC structure, and am developing my own MVC framework for a university project. I've got a database class that I can use to send a query to the database and return me an array of objects (PHP standard object class). I then want to display a list of the objects on an index page.
My question is, should this list of standard objects really be a list of models? Or are they fine as they are?
You don't have to create separate model classes just for the sake of creating model classes because they are in the MVC pattern name. If your solution also works when you simply pass the array of PHP standard object classes to your view, you should just use that. In that case creating model classes would just be extra work for no benefit. However, if you need additional functionality besides simply outputting a list of database results, you should consider creating actual models.
You should store data in your database and manipulate this data (create,update,read and destroy) with your models. I think you should better know what is MVC and what is for. You can read a bit here
depends... One could argue that most applications are very heavy on the Model side (Fat Models is an actual pattern), therefore it will not be enough to create a few stdObjects from an array, but actually map tables to object classes, so you can add useful methods to them.
I would recommend to take a look at Doctrine and try implementing a subset of features.
I am wondering whats the best practices regarding functions and objects. For example I want to perform an action called tidy. It will take my data as input and tidy it and return it.
Now I can do this in two ways. One using a simple function and the other using a class.
Function: $data = tidy($data);
Class:
$tidy = new Tidy();
$data = $tidy->clean($tidy);
Now the advantage in making it a class is that I do not have to load the class before. I can simply use the autoload feature of php to do so.
Another example is the database class. Now everyone seems to be using a separate class for db connectivity. But we usually have a single object of that class only. Isn't this kind of contrary to the definition of class and objects in a sense that we are using the class only to intantiate a single object?
I kind of dont understand when to use a function and when to use a class. What is the best practice regarding the same? Any guidelines?
Thank you,
Alec
For something that does one thing, and only one thing, I'd just use a function. Anything more complex, and I'd consider using an object.
I took the time to poke through some piles of (arguably ugly and horrible) PHP code and, really, some things could have been done as objects, but were left as functions. Time conversions and string replacements.
Functions typically do one specific task.
Objects represent something that have tasks associated with it. (methods)
Use a function for tidy. Plain and simple. ;-)
I'd personally make a 'data' object that handles data then have a tidy method under it.
This pattern will allow the number of tasks you do on data to expand while containing it all in a nice little self-contained chunk.
For your case, I'd make it a function, possibly a static function in something like a "util" class (for which the only purpose of the class is to act like a namespace - it'll group all your random useful methods together). As a rule of thumb, only use an object if it needs to store some data that needs to live between multiple function calls. That's why the database methods are made to be part of an object, because they store a database handle which is used between multiple function calls. Yes, there only ever is one database object, but having it as an object groups all the database-related stuff into one place, making it easier to maintain and keep bug-free.