I'm pretty new to OOP and been programming in it successfully in terms of getting things to work but I have found I keep running into a similar problem and am not sure what to 'Google query' to get answers.

Basically I have 3 classes, projects, clients, people. I run into the issue of what is the best way to access each from each other.

For instance, I want to grab all projects based on the current client and there are a couple of ways I have thought of how to do this but do not know the 'best' way to do it.

1: have a method in the client class that grabs all the project info, store a multi-dimensional array, foreach said array to extract data2: have a method in the client class that creates multiple project objects and store in an array to do a foreach on3: create a new object using the project class and pass the client id to it

Advantages/Disadvantages (that I can think of)1: (probably the worst idea) creates possibility of multiple methods in multiple classes that do almost/same thing however leaves all the projects in the client object2: same as above but keeps everything more object oriented3: seems like the right choice but now there's no 'easy way' to connect the projects to the client (for instance if I have n number of clients i can no longer just do $client->projects->name (I know I could do ${'clients'.$x} and ${'projects'.x} but that seems un-needed, like I'm missing an important step/concept of oop).

Any thoughts, opinions, insights from anyone? Any help is greatly appreciated.

@ServerStorm I am using a database, mysql, using prepared msyqli statements.

At the moment I'm going with option 2 as it seems to make the most sense to me (keeping some sort of hierarchy while keeping things together and still all in object form). I'd still love to hear insight. An Object with an array of other objects in it seems a little weird but I am new to OOP.

You may be better off creating a 4th class -- let's call it ProjectDatabase. This class can be responsible for mapping objects to database tables, and it can have methods such as findProjectsByClient that would fetch the data and create the objects with the appropriate relations.

hmm, yeah, that might be better..cause right now I just realized I created the horrible monstrosity of an object with an array of objects down to a 4th level...basically: $client->project[$x]->item[$y]->subitem[$z] :/

hmm, yeah, that might be better..cause right now I just realized I created the horrible monstrosity of an object with an array of objects down to a 4th level...basically: $client->project[$x]->item[$y]->subitem[$z] :/

Hi Justin,

Anytime you get 'monstrosities' in objects, it is a good indicator for re-factoring. Are you willing to post your classes so we can help re-factor them? I am not sure but it 'sounds' like your objects are taking on roles that go beyond discrete logic although it is hard to tell given what you have said so far.

There are probably several issues with the code...so any other things to point would also be greatly apperciated.I haven't gotten the hang of exceptions quite yet either...so the return false without closing the stmt are probably bad...

Your Project class is using an Active Record Pattern to manage your communication with the Db, which is is the simplest of the different ways in which databases are related to in an application. Active Record leads relatively high degree of coupling between the application code and database structure. However this coupling is likely far easier to manage than adopting a more complex database pattern. The next genesis of this could be using a Table Data Gateway Pattern, which resembles the Active Record, only you implement gateways to manipulate all rows in a specific table, I don't think it is required to do this; others may disagree.

For testing I dropped in a database class that I use sometime for testing. You can see that the project class itself initiates the db so it has been removed for the container class.

You can also see that I changed the visibility of your properties from public to protected. You don't want someone messing with these properties without using a method you enforce as a public api, so for this the only places most of these properties can be set is at the Project Class instantiation or through a setter. I have created one setter set_id(id) as originally you had this located as a parameter on the Project Class's select_project() method. However you reference $this->id in most of your other methods so being able to set an id and then directly call on of these methods provides greater flexibility.

You have nice use of prepared statements and a clean coding/naming style, so it was good to work with your code.

@ServerStorm - Finally had a chance to look at the code and I only have one question about the construct of the Project class calling a new connection. If I had say 4-6 projects and they are all creating a new db connection inst that bad or is it effectively the same thing as what I was doing? I was just reusing the same db connection (not sure if that's bad as well...) and passing it through to the objects.

Also, would you recommend the set/get magic methods or make a set_PROPERTY method for each property?

You want to share the database handle in an application because it's an overhead to keep opening and closing connections, particularly during a single page fetch.

The14thGOD said:

@ServerStorm - Finally had a chance to look at the code and I only have one question about the construct of the Project class calling a new connection. If I had say 4-6 projects and they are all creating a new db connection inst that bad or is it effectively the same thing as what I was doing? I was just reusing the same db connection (not sure if that's bad as well...) and passing it through to the objects.

Also, would you recommend the set/get magic methods or make a set_PROPERTY method for each property?

Hi The14thGOD,You might want to share things like the database handle in your application because of the overhead to keep opening and closing connections, particularly when doing a single page fetch. Is it bad not to not share the db handle? It depends on how many connections you establish; it may be fine doing it your original way in the container or via the constructor.

I put this in the constructor of the Projects class so that Project class knows its' own dependencies. It again is debatable whether you do it your way or the constructor way as neither are perfect, but can certainly be valid choices.

Here is an example of how you might use a Singleton to share your Db connections:

This can get a little tricky if you need to do connection pooling in the future. if you do need to do this then it would be implemented in the getConnection() method.

As far as the set/get magic, it can make it hard for others and even yourself (long times away from the code to see what is happening; although your application would be good to do this as your set/get requirements shown are straight forward so hard to get lost in. Of course this can change

public function select_revisions(){
//get all revisions based on project id and return them as an array
$revisions = Revision::select_revisions($this->id);
}

Which would then call a function in the revision class that is basically the same as the first code section above.

Is this the best way to approach this or do you have any other insights I should pursue? The reason why I'm worried is because the relationship is like this:Client->project->revisions->images->comments

In a variable way it would look something like:$client->project[0]->revision[0]->images[0]->comments[0]

This would access the first comment of the first image of the first revision on project 1 for client X.

This is the only way I can think of to try and keep all the different classes separate but still be able to access them and keep them related to each project.If this doesn't make sense I can try and explain it better...

So that we can better understand, can you in words describe how clients, projects, revision, images and comments. This exercise might help us decide if the class modeling you have done is appropriate or if we refactor it in a different way.

Each client has multiple projects, each of these projects have revisions (versions of a project basically). Each revision has a series of images (as an example lets say that project is a website. Images could include: home, contact, about, etc). Each image has comments (users (who are attached to the client) can make comments about how that page is designed etc).

Hopefully that clears it up a bit... I know it can be hard to understand esp without images/wireframes.

What your talking about is really complicated topic and much the reason for libraries such as; doctrine exist. If you want to look more into it I suggest reading about lazy and eager loading. That is essentially what you are trying to achieve which are very advanced topics that tend to both have their strong and low points. Wish it were more simple but really it is not. You either run multiple queries to gather the data (lazy loading) or use joins and map that data to the proper model instance (eager loading). Which can become very painful if you don't have an automated/generic library to do it with. I'll expand on it some more based on your example.

$client->project[0]->revision[0]->images[0]->comments[0]

In the "lazy" methodology

$client->project

Would result in a hit to the db for all projects for the client.

$client->project[0]->revision

Would result in yet another query for the projects revisions

$client->project[0]->revision[0->images

Would result in yet another query for all the revisions images.

$client->project[0]->revision[0]->images[0]->comments

Would result in yet another query for all the images comments.

Now this may not look to bad if you only dealing with a single project on the page. However, imagine if you had to list 50 projects on the page and the active revisions image. That could potentially be over 200 queries. This is a very real problem and one even the creator pf the phpdatamapper had never concurred in automated fashion besides for eager loading and custom mapping

The other option is taking the hit initially, storing the objects in a cache and fetching them from there before hitting the db. That is the approach libraries such doctrine take ( I think phpdatamapper uses caching to). However, that means that you will always have to fetch all data associated with the object. What are referred to as "partials" only a specific collection of fields from a table/object is not really recommended given a caching model since objects can easily become out of sync that way. Especially a caching model that persists beyond the lifetime of a page request using something like memcache, which I believe is the preferred method in Doctrine.

Now the other option – eager loading.

Eager loading would be to create a big, gigantic query that performs all the joins necessary to collect all that data. This would ideally be a single query. Than map that data to each domain level instance, which can be very tricky. In this case it would because there are so many levels of the hierarchy. Not to mention you would really need to make this a single method because it wouldn't be practical to fetch all this other, related data if you only needed something at the root, project level. Though the obvious advantage of the eager method is that given 50 items a single query could be executed to collect the relational data for each level of the relational hierarchy.

Not having a way to automate either eager or lazy loading is going to result in some painful, redundant code. That is much the reason libraries like doctrine are popular. To deal with mess of converting/mapping database tables or collection of tables to domain level entities that can be managed in a object oriented fashion. I'm not saying use doctrine but yeah… it is a complex topic.

If your not using a library to mange the mapper implementation than you are probably better off using a dao and returning associative arrays. That would be nothing more than creating a class to manage "projects" and methods that return exactly the data set you need given a circumstance. That is actually the model I am using on a in progress CMS I'm working on for many of the reasons mentioned above. Here is a quick example just so you can get an idea.

The main idea is that I forget about mapping and merely encapsulate all data access logic in this class – simple. Not nearly as powerful or cool as active record or data mapper but it is much less code and I don't mind writting queries. So yeah…

The only thing that tends to suck is listAll methods which I need to control filters, sorting, limits, etc from outside. The way it is now my application code does need to know something about the tables which are being hit, but I have yet to figure out an elegant way to change that without a whole bunch more code or inventing my own ActiveRecord or ORM.

Oddz, thanks for the detailed post. I will look more into the 'lazy' and 'eager' loading methods, I think I got a pretty good concept, but more details are always good to have. Not sure if it applies to all the tools, but I know I can't use memcache because I'm on a shared host. If I had the money I'd shell out for a dedicated server. When you mention 'map to domain' does that refer to matching say /project/ with the project table? Similar to how the MVC method works? (which I still don't get, I understand the concept, but actually putting it into practice I get lost (topic for another day)). I'll have to look at more info on the rest of your post as it's over my head a bit but I am glad to know it's not an easy question I had to begin with.