From: Arlo L. <ar...@ar...> - 2009-06-10 18:01:26
|
Hi folks, I'm doing my first project with a fully object-oriented approach and I have a question about how you all would break the code apart. Let's say I have a social networking site where members can upload photos, and I want to display a particular member's photos. One approach is to have a Member object, with a method getPhotos, that returns the IDs of the photos that belong to that member; and to have a Photo object, with a method getDetails, that returns the details for a given photo. In order to display a member's photos, I would first call getPhotos for the member, then call getDetails for each of the returned photos. This makes sense from an encapsulation perspective, but it seems wasteful because I'd have one initial database query plus an additional query for each photo. I could build getDetails so that it can take a list of IDs and return the details for all the photos at once, and then I'd just have two queries. Or I could build a getPhotosByMember method that accepts a member ID as an argument and returns the details for all the photos belonging to that member. Then I'd be down to one query, but I would probably end up building several similar methods (e.g., getRecentPhotos) that would have redundant code. What would you say is the normal or accepted way to structure this? Thanks, -Arlo _______________________________ Arlo Leach 773.769.6106 http://arlomedia.com |
From: Richard L. <ce...@l-...> - 2009-06-10 19:05:47
|
I would write it such that the getFoo() could accept multiple IDs, across the board. If every time you getPerson, you *always* get the Photos and Details, then just do one big-ass query... That's probably not the way it is. Instead, use some kind of cache to cache the results for a reasonable amount of time. Possibly with an easy peasy lemon squeezy way to purge it for specific user and/or photo and/or detail, when an insert/update happens. If you expect heavy load, read up on the trials and tribulations Facebook and others have gone through, because you can expect the same :-) On Wed, June 10, 2009 12:33 pm, Arlo Leach wrote: > Hi folks, > > I'm doing my first project with a fully object-oriented approach and I > have > a question about how you all would break the code apart. > > Let's say I have a social networking site where members can upload > photos, > and I want to display a particular member's photos. > > One approach is to have a Member object, with a method getPhotos, that > returns the IDs of the photos that belong to that member; and to have > a > Photo object, with a method getDetails, that returns the details for a > given > photo. In order to display a member's photos, I would first call > getPhotos > for the member, then call getDetails for each of the returned photos. > This > makes sense from an encapsulation perspective, but it seems wasteful > because > I'd have one initial database query plus an additional query for each > photo. > > I could build getDetails so that it can take a list of IDs and return > the > details for all the photos at once, and then I'd just have two > queries. Or I > could build a getPhotosByMember method that accepts a member ID as an > argument and returns the details for all the photos belonging to that > member. Then I'd be down to one query, but I would probably end up > building > several similar methods (e.g., getRecentPhotos) that would have > redundant > code. > > What would you say is the normal or accepted way to structure this? > > Thanks, > -Arlo > > _______________________________ > > Arlo Leach > 773.769.6106 > http://arlomedia.com > > > > > ------------------------------------------------------------------------------ > Crystal Reports - New Free Runtime and 30 Day Trial > Check out the new simplified licensing option that enables unlimited > royalty-free distribution of the report engine for externally facing > server and web deployment. > http://p.sf.net/sfu/businessobjects > _______________________________________________ > chiPHPug-discuss mailing list > chi...@li... > https://lists.sourceforge.net/lists/listinfo/chiphpug-discuss > -- Some people ask for gifts here. I just want you to buy an Indie CD for yourself: http://cdbaby.com/search/from/lynch |
From: Arlo L. <ar...@ar...> - 2009-06-13 06:31:59
|
Hi folks, Thanks for your feedback on this question! In particular... Rich wrote: > I would write it such that the getFoo() could accept multiple IDs, > across the board. This is the direction I've taken and it seems to be going well. For example, if I have a Orders class then it will include a getOrders method that can take a list of IDs and return a result set. And I've made getOrders a static method so that I can call it any time without having to instantiate an orders object. There's just one thing that bothers me about this. I can see the value of instantiating an object if I want to do a lot of work with it -- like if I have a multi-page order form that incrementally collects data and uses methods like calculateShipping and calculateTaxes along the way. But if I just want to view a list of orders, and I just call the static getOrders method, then I might as well be calling an ordinary function. It's still helpful to have all the functions relating to orders in one place, but is it weird to use the same Orders class in two fundamentally different ways? I guess what I'm saying is that classes have been useful throughout the site, but objects have only been useful in a few places. Kenneth wrote: > It's far more efficient to issues smart and efficient queries that > return associative arrays, and then have classes that know what to do > with those arrays. Can you elaborate on that? I think I agree but I wonder where you would put those SQL queries. So far I've been able to put all of my queries inside my classes without any special effort, and I'm liking that level of abstraction from the database. The classes are performing the queries and giving back arrays to the main page code. Matt wrote: > It appears your objects are just representations of data tables? > In our system we use a base class row.inc that handles a lot of the data > access and base functionality all classes need. > All other objects extend this class. I'm doing a similar thing with a Base class that provides some common functionality to all the other classes. For example, it can save and retrieve data from a session for that multi-page order form I mentioned above. I'm really digging the inheritance capabilities ... adding a new feature to the Base class makes it instantly available throughout the site. Wilfried wrote: > I personally don't spend tons of time going out of my way to make my > code all OOP'ed up just for the sake of OOP. For some things, OOP just > isn't the right axe. Agreed, but I'm already seeing some benefits with this project. I'll be able to share a lot more code between the public site and the admin interface, for example. Larry wrote: > Not only is it a good history lesson, this article is also spot-on about the > challenges of OO software and relational databases: > > http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx My goodness! Well, I'm relieved to hear that I'm not the only one who's feeling a little mixed up about this. Cheers, -Arlo _______________________________ Arlo Leach 773.769.6106 http://arlomedia.com |
From: Richard L. <ce...@l-...> - 2009-06-10 19:10:41
|
PS Person, Photo, Details are the obvious Objects to use. Obvious does not always equal Right. :-) Keep an open mind about using People and Albums as objects, and the details within are just an array, particularly if you expect to be dealing with a LOT of people in any single page. Or even something even more non-obvious. I've often found in OOP that after I write the whole thing in the obvious way, and then really sit down and Zen on it for a long time, that if I had just looked at it all "sideways" from the get-go, a much better/cleaner OOP hierarchy would have come out... But there's no easy way to do that until you've figured out your entire Feature Set and spent a LOT of time thinking about what you really want to do. On Wed, June 10, 2009 12:33 pm, Arlo Leach wrote: > Hi folks, > > I'm doing my first project with a fully object-oriented approach and I > have > a question about how you all would break the code apart. > > Let's say I have a social networking site where members can upload > photos, > and I want to display a particular member's photos. > > One approach is to have a Member object, with a method getPhotos, that > returns the IDs of the photos that belong to that member; and to have > a > Photo object, with a method getDetails, that returns the details for a > given > photo. In order to display a member's photos, I would first call > getPhotos > for the member, then call getDetails for each of the returned photos. > This > makes sense from an encapsulation perspective, but it seems wasteful > because > I'd have one initial database query plus an additional query for each > photo. > > I could build getDetails so that it can take a list of IDs and return > the > details for all the photos at once, and then I'd just have two > queries. Or I > could build a getPhotosByMember method that accepts a member ID as an > argument and returns the details for all the photos belonging to that > member. Then I'd be down to one query, but I would probably end up > building > several similar methods (e.g., getRecentPhotos) that would have > redundant > code. > > What would you say is the normal or accepted way to structure this? > > Thanks, > -Arlo > > _______________________________ > > Arlo Leach > 773.769.6106 > http://arlomedia.com > > > > > ------------------------------------------------------------------------------ > Crystal Reports - New Free Runtime and 30 Day Trial > Check out the new simplified licensing option that enables unlimited > royalty-free distribution of the report engine for externally facing > server and web deployment. > http://p.sf.net/sfu/businessobjects > _______________________________________________ > chiPHPug-discuss mailing list > chi...@li... > https://lists.sourceforge.net/lists/listinfo/chiphpug-discuss > -- Some people ask for gifts here. I just want you to buy an Indie CD for yourself: http://cdbaby.com/search/from/lynch |
From: matt d. <mm_...@ya...> - 2009-06-10 19:28:48
|
Hey Arlo, It appears your objects are just representations of data tables? In our system we use a base class row.inc that handles a lot of the data access and base functionality all classes need. All other objects extend this class. * The row class acts as a frame for a MySQL row * which provides a simple interface for accessing and saving data. When a descendent object is created, it loads * the columns and all data of a particular row ID in a MySQL table into the row->columns and row->data * members, respectively. To save, new values are loaded into the associated array row->data_pending, * which the row->save() method uses. Upon saving, if a field in $data_pending is not equal to the same field in $data * the validate() method is called, which a class derived from row can use to check or alter the new data. * <p> * Data is usually not accessed directly via the row->data array but instead is accessed using PHP5's method and parameter overloading, when an arbitrarily named $member of row is accessed (as in row->$member), row->__get() will be called which in turn calls row->$member(), if the method doesnt exist row->__call() will then be invoked. __call() takes the following steps: 1. check if row->data[$member] exists, if it does, that value is returned 2. invoke row->child_call($member). * Usually row->child_call() is overloaded and the developer will use switch($member) to add their own methods or values for each particular type of table, the results of which should be stored in row->data within the child_call method (no value is returned). * So this function below basically accesses any column data or can be used to create a new function. function child_call($nm,$argv) { // cut and paste this when deriving new classes from row $r = &$this->data[$nm]; // make a shorter alias switch($nm) { default: unset($this->data[$nm]); return -1; } } If you want I'll send a more complete example but, basically we would use some other utilities like "getQueryObjects" which is like it sounds- so in your example a query would be "select * from photos where user_id = $ID" and you would tell the function to return an array of photo objects. $photos = getQueryObjects("select * from photos where user_id = $ID","photo"); Then we just use the convention <$= $photo->description() ?> if we want to display any of the row data or call a user defined function in the class. ________________________________ From: Arlo Leach <ar...@ar...> To: Chicago PHP User Group <chi...@li...> Sent: Wednesday, June 10, 2009 12:33:12 PM Subject: [chiPHPug-discuss] OOP structuring question Hi folks, I'm doing my first project with a fully object-oriented approach and I have a question about how you all would break the code apart. Let's say I have a social networking site where members can upload photos, and I want to display a particular member's photos. One approach is to have a Member object, with a method getPhotos, that returns the IDs of the photos that belong to that member; and to have a Photo object, with a method getDetails, that returns the details for a given photo. In order to display a member's photos, I would first call getPhotos for the member, then call getDetails for each of the returned photos. This makes sense from an encapsulation perspective, but it seems wasteful because I'd have one initial database query plus an additional query for each photo. I could build getDetails so that it can take a list of IDs and return the details for all the photos at once, and then I'd just have two queries. Or I could build a getPhotosByMember method that accepts a member ID as an argument and returns the details for all the photos belonging to that member. Then I'd be down to one query, but I would probably end up building several similar methods (e.g., getRecentPhotos) that would have redundant code. What would you say is the normal or accepted way to structure this? Thanks, -Arlo _______________________________ Arlo Leach 773.769.6106 http://arlomedia.com ------------------------------------------------------------------------------ Crystal Reports - New Free Runtime and 30 Day Trial Check out the new simplified licensing option that enables unlimited royalty-free distribution of the report engine for externally facing server and web deployment. http://p.sf.net/sfu/businessobjects _______________________________________________ chiPHPug-discuss mailing list chi...@li... https://lists.sourceforge.net/lists/listinfo/chiphpug-discuss |
From: Wilfried S. <ws...@de...> - 2009-06-10 19:39:16
|
This could be very expensive, but if you want to truly go all out OOP/ ORM-like, have you thought about returning an object instead of returning a list or array? This object could perhaps mirror/extend a pre-defined one, with functions that then go off and fetch the details? Ex: $member = new Member($member_id); $photos = $member->getPhotos(where $query=''); //gets all photos, results in $photos $details = $photos->getDetails(); //gets all details about $photos, results in $details? or perhaps getDetails() just populates $photos further, no need for the return? whatever is prettier to you. with $member containing the member data in a way thats useful to the methodsin the object with $photos containing the data of the getPhotos query thats userful to methods within a photos structure with $details somehow containing some stdclass structure/array/ whatever that contains what youre looking for in an interable method. This way you avoid having to iterate and do individual queries. Then again, you might actually want to do that. I don't know what your workload looks like or if it even matters. With the getDetails() function as above, it gives you the option to query as you'd like. I'd personally throw the IDs in a IN() query limited to 20 ids per each query, post multiget on my cache (The 20 limit is to avoid innodb mvcc deadlocks on high concurrency systems, ymmv). I'd be interested to see how others disagree with me on this. I personally don't spend tons of time going out of my way to make my code all OOP'ed up just for the sake of OOP. For some things, OOP just isn't the right axe. On Jun 10, 2009, at 13:33 , Arlo Leach wrote: > Hi folks, > > I'm doing my first project with a fully object-oriented approach and > I have > a question about how you all would break the code apart. > > Let's say I have a social networking site where members can upload > photos, > and I want to display a particular member's photos. > > One approach is to have a Member object, with a method getPhotos, that > returns the IDs of the photos that belong to that member; and to > have a > Photo object, with a method getDetails, that returns the details for > a given > photo. In order to display a member's photos, I would first call > getPhotos > for the member, then call getDetails for each of the returned > photos. This > makes sense from an encapsulation perspective, but it seems wasteful > because > I'd have one initial database query plus an additional query for > each photo. > > I could build getDetails so that it can take a list of IDs and > return the > details for all the photos at once, and then I'd just have two > queries. Or I > could build a getPhotosByMember method that accepts a member ID as an > argument and returns the details for all the photos belonging to that > member. Then I'd be down to one query, but I would probably end up > building > several similar methods (e.g., getRecentPhotos) that would have > redundant > code. > > What would you say is the normal or accepted way to structure this? > > Thanks, > -Arlo > > _______________________________ > > Arlo Leach > 773.769.6106 > http://arlomedia.com > > > > > ------------------------------------------------------------------------------ > Crystal Reports - New Free Runtime and 30 Day Trial > Check out the new simplified licensing option that enables unlimited > royalty-free distribution of the report engine for externally facing > server and web deployment. > http://p.sf.net/sfu/businessobjects > _______________________________________________ > chiPHPug-discuss mailing list > chi...@li... > https://lists.sourceforge.net/lists/listinfo/chiphpug-discuss |
From: Richard L. <ce...@l-...> - 2009-06-11 15:13:22
|
This came through just fine. You may have set up mailman to not show you your own posts... I think that's one of the options in the setup on the list preferences. On Wed, June 10, 2009 2:10 pm, Wilfried Schobeiri wrote: > This could be very expensive, but if you want to truly go all out OOP/ > ORM-like, have you thought about returning an object instead of > returning a list or array? This object could perhaps mirror/extend a > pre-defined one, with functions that then go off and fetch the > details? > > Ex: > $member = new Member($member_id); > $photos = $member->getPhotos(where $query=''); //gets all photos, > results in $photos > $details = $photos->getDetails(); //gets all details about $photos, > results in $details? or perhaps getDetails() just populates $photos > further, no need for the return? whatever is prettier to you. > > with $member containing the member data in a way thats useful to the > methodsin the object > with $photos containing the data of the getPhotos query thats userful > to methods within a photos structure > with $details somehow containing some stdclass structure/array/ > whatever that contains what youre looking for in an interable method. > > This way you avoid having to iterate and do individual queries. Then > again, you might actually want to do that. I don't know what your > workload looks like or if it even matters. With the getDetails() > function as above, it gives you the option to query as you'd like. I'd > personally throw the IDs in a IN() query limited to 20 ids per each > query, post multiget on my cache (The 20 limit is to avoid innodb mvcc > deadlocks on high concurrency systems, ymmv). > > I'd be interested to see how others disagree with me on this. I > personally don't spend tons of time going out of my way to make my > code all OOP'ed up just for the sake of OOP. For some things, OOP just > isn't the right axe. > > > On Jun 10, 2009, at 13:33 , Arlo Leach wrote: > >> Hi folks, >> >> I'm doing my first project with a fully object-oriented approach and >> I have >> a question about how you all would break the code apart. >> >> Let's say I have a social networking site where members can upload >> photos, >> and I want to display a particular member's photos. >> >> One approach is to have a Member object, with a method getPhotos, >> that >> returns the IDs of the photos that belong to that member; and to >> have a >> Photo object, with a method getDetails, that returns the details for >> a given >> photo. In order to display a member's photos, I would first call >> getPhotos >> for the member, then call getDetails for each of the returned >> photos. This >> makes sense from an encapsulation perspective, but it seems wasteful >> because >> I'd have one initial database query plus an additional query for >> each photo. >> >> I could build getDetails so that it can take a list of IDs and >> return the >> details for all the photos at once, and then I'd just have two >> queries. Or I >> could build a getPhotosByMember method that accepts a member ID as >> an >> argument and returns the details for all the photos belonging to >> that >> member. Then I'd be down to one query, but I would probably end up >> building >> several similar methods (e.g., getRecentPhotos) that would have >> redundant >> code. >> >> What would you say is the normal or accepted way to structure this? >> >> Thanks, >> -Arlo >> >> _______________________________ >> >> Arlo Leach >> 773.769.6106 >> http://arlomedia.com >> >> >> >> >> ------------------------------------------------------------------------------ >> Crystal Reports - New Free Runtime and 30 Day Trial >> Check out the new simplified licensing option that enables unlimited >> royalty-free distribution of the report engine for externally facing >> server and web deployment. >> http://p.sf.net/sfu/businessobjects >> _______________________________________________ >> chiPHPug-discuss mailing list >> chi...@li... >> https://lists.sourceforge.net/lists/listinfo/chiphpug-discuss > > > ------------------------------------------------------------------------------ > Crystal Reports - New Free Runtime and 30 Day Trial > Check out the new simplified licensing option that enables unlimited > royalty-free distribution of the report engine for externally facing > server and web deployment. > http://p.sf.net/sfu/businessobjects > _______________________________________________ > chiPHPug-discuss mailing list > chi...@li... > https://lists.sourceforge.net/lists/listinfo/chiphpug-discuss > -- Some people ask for gifts here. I just want you to buy an Indie CD for yourself: http://cdbaby.com/search/from/lynch |
From: Kenneth D. <ke...@se...> - 2009-06-11 14:14:25
|
Arlo Leach wrote: > Hi folks, > > I'm doing my first project with a fully object-oriented approach and I have > a question about how you all would break the code apart. > > Let's say I have a social networking site where members can upload photos, > and I want to display a particular member's photos. > > One approach is to have a Member object, with a method getPhotos, that > returns the IDs of the photos that belong to that member; and to have a > Photo object, with a method getDetails, that returns the details for a given > photo. In order to display a member's photos, I would first call getPhotos > for the member, then call getDetails for each of the returned photos. This > makes sense from an encapsulation perspective, but it seems wasteful because > I'd have one initial database query plus an additional query for each photo. > OOP is an amazing and wonderful thing, when used in its context. Discovering the context is simple in black-and-white cases. The user interface lends itself very nicely to OOP concepts, and I've found UI's much easier to build with the OOP approach. Mapping to the database is more of a gray area because the database operates on different principles. Where the code meets the database you have a decision about how to proceed. The ORM approach, which is what you are describing above, makes the database look like objects. The problem is that a database is not a collection of objects. As you say, "...it seems wasteful because I'd have on initial database query plus..." That in a nutshell is what happens when the database is forced into the OOP mindset. It's far more efficient to issues smart and efficient queries that return associative arrays, and then have classes that know what to do with those arrays. A "photos" class need only know what to do with one or more photos, there is no reason that it must be used as one-object-per-row in the database. As long as it knows what to do with photos, it should handle them in the most efficient way possible. Creating one object per database row is rarely the most efficient, if ever. > I could build getDetails so that it can take a list of IDs and return the > details for all the photos at once, and then I'd just have two queries. Or I > could build a getPhotosByMember method that accepts a member ID as an > argument and returns the details for all the photos belonging to that > member. Then I'd be down to one query, but I would probably end up building > several similar methods (e.g., getRecentPhotos) that would have redundant > code. > > What would you say is the normal or accepted way to structure this? > > Thanks, > -Arlo > > _______________________________ > > Arlo Leach > 773.769.6106 > http://arlomedia.com > > > > > ------------------------------------------------------------------------------ > Crystal Reports - New Free Runtime and 30 Day Trial > Check out the new simplified licensing option that enables unlimited > royalty-free distribution of the report engine for externally facing > server and web deployment. > http://p.sf.net/sfu/businessobjects > _______________________________________________ > chiPHPug-discuss mailing list > chi...@li... > https://lists.sourceforge.net/lists/listinfo/chiphpug-discuss > -- Kenneth Downs Cell: 631-379-0010 Fax: 631-689-0527 ke...@se... http://www.secdat.com http://www.andromeda-project.org |
From: Larry G. <la...@ga...> - 2009-06-12 05:12:19
|
On Thursday 11 June 2009 7:43:48 am Kenneth Downs wrote: > OOP is an amazing and wonderful thing, when used in its context. > > Discovering the context is simple in black-and-white cases. The user > interface lends itself very nicely to OOP concepts, and I've found UI's > much easier to build with the OOP approach. > > Mapping to the database is more of a gray area because the database > operates on different principles. Where the code meets the database you > have a decision about how to proceed. Not only is it a good history lesson, this article is also spot-on about the challenges of OO software and relational databases: http://blogs.tedneward.com/2006/06/26/The+Vietnam+Of+Computer+Science.aspx One of the things I really like about PHP is that it lets you mix and match procedural, OO, and in 5.3 functional code to match your use case. Don't assume that one approach is always better. It's been shown mathematically that there is no problem that cannot be solved in all three approaches. It's just often much easier to solve a given problem in one of them, and a different problem in another. Right tool for the job and son on. -- Larry Garfield la...@ga... |