> I don't know of any good books for patterns. I'm quite happy with "Design Patterns Explained." It's great for the relative novice who's interested in design patterns.
Design Patterns Explained Alan Shalloway, James R. Trott Addison-Wesley, 2001 ISBN: 0201715945 Edward Dudlik Becoming Digital www.becomingdigital.com ----- Original Message ----- From: "Robert Cummings" <[EMAIL PROTECTED]> To: "Gerard Samuel" <[EMAIL PROTECTED]> Cc: "Jay Blanchard" <[EMAIL PROTECTED]>; "PHP-General" <[EMAIL PROTECTED]> Sent: Friday, 03 October, 2003 13:45 Subject: Re: [PHP] Committing OO Sin On Fri, 2003-10-03 at 12:40, Gerard Samuel wrote: > Jay Blanchard wrote: > > >Global space? Yes, what you're talking about, if possible, is a sin. > > > >Why is getting the classes to work together a pain? > > > A little misleading about what Im feeling. > Im feeling that the more classes that I add the more cumbersome things get, > and at the rate Im going, I get the feeling my code will self destruct > (figure of speech). > For example. I have another class that handles comments. > This class currently takes the smarty class by reference, which contains > the DB class by reference. > If I were to convert the user management file to a class, > then the comments class will also have to contain the user management > class which contains, > a reference to the DB class. > The whole class paradim, just gets uglier and uglier in my case. > I have to stop and rethink about how to make classes work together better. > Robert Cummings made a suggestion to me in an earlier topic about > singleton patterns, > and again, in this topic about frameworks (basically a design pattern > from what I've been reading so far this past week). > Im just not sure how to proceed, and the thought occured to me to use > $GLOBALS like > $GLOBALS['db']->Execute('some sql'); > $GLOBALS['smarty']->fetch('that template'); > > Im going to have to invest in a book on frameworks (design patterns), as > I can't see myself continuing down > the road Im presently on. > > Im open to any suggestions on books. Im currently reading up on > articles at phppatterns.com, hopefully some of it > will sink in. I don't know of any good books for patterns. much of what I know I learned in university and from experience. But to take your problem and perhaps give you a window on how you can organize things I will try to lay out a possible plan. Known classes: - User manager (um) - db connection (dbc) - smarty (smarty) - comments (comments) Relationships: - um uses smarty, dbc - smarty uses dbc - comments uses um Proposal: - middle man (mm) it's almost imperative to have a middle man class that can return necessary instances of object (whether it be multiple instances or a singleton). In InterJinn this middle man class is the dynamic loader. - database manager (dbm) to return database connections. This could be a pooling mechanism for a given connection so that you only ever return one connection. This has a problem though if you wish to do a query based on the results of another query without storing all the data from the first query. There really isn't much difference in processing time when using a pool and when returning a new connection. InterJinn uses a pool for the default MySQL database layer, but not for the Pear DB database layer. Pear DB may use its own pool, but that's not for the user of the class to care about (black box coding). - dbc is a single connection, whether it be pooled or not. The only guarantee you should have is that it won't interfere with another query (if pooled then the dbm should only return the same connection if it has been freed. - um should be a factory, you give it a userId, or name and it returns a user object which the appropriate methods to retrieve/store user information. - user object (user). Singleton for a given user (don't want to update multiple copies of a single user object). The um can pool user objects according to user Id and return references when requested. - I'm not sure why smarty has a reference to a database connection in your code (though I'm not greatly familiar with Smarty since I've only used it in conjunction with other people's code that was already using it). At any rate, unless you are extending the smarty class, then you should give it it's own database connection to use. if you wanted you could always create a smarty manager layer to retrieve smarty objects, but this probably isn't necessary for your own work. - the connection object isn't used by anything, so it should just be a regular object. For simplicity I'm going to assume I made all my management objects part of the middle man class with a very simple interface: lets say I have code that needs to display user stats, comments, and via a smarty template. I might have the following: <?php include_once( 'middleMan.inc' ); include_once( 'Smarty.class.inc' ); mm = new MiddleMan(); $userId = $_SESSION['userId']; // Reference since proposal called for a singleton user system. $user = &$mm->getUser( $userId ); $comment = new Comment(); // // Not sure what the purpose of comments are, so I'll just skip // details. // $template = new Smarty(); $template->assign( 'USER_NAME', $user->getName() ); $template->assign( 'USER_ADDRESS', $user->getAddress() ); $template->assign( 'COMMENTS', $comment->getText( $userId ) ); $template->display( 'someTemplate.tpl' ); ------------------------------------------------------------------- That's the bulk of the main page, now inside $mm->getUser() ------------------------------------------------------------------- function &getUser( $userId ) { if( isset( $this->userCache[$userId] ) ) { return $this->userCache[$userId]; } // gotta look it up in DB (NOTE that the $myParams could // be set as a default in the getDbConnection() method). $dbc = $GLOBALS['mm']->getDbConnection( $myParams ); $dbc->query( "SELECT from users ... WHERE user_id = $userId" ); // create user object. $user = new User(); // // set user object data with data from DB. // $dbc->free(); $this->userCache[$userId] = &$user; return $user; } ------------------------------------------------------------------ Not too bad so far. Now for the gettext() method of the comments ------------------------------------------------------------------ function getText( $userId ) { // gotta look it up in DB (NOTE that the $myParams could // be set as a default in the getDbConnection() method). $dbc = $GLOBALS['mm']->getDbConnection( $myParams ); $dbc->query( "SELECT from comments ... WHERE user_id = $userId" ); $text = $dbc->getField( 'content' ); $dbc->free(); return $text } ------------------------------------------------------------------ Ok well that's it for the most part. Feel free to ask questions, and anyone else can feel free to critique :) This is obviously extremely glossed over, but it illustrates how the only necessary global variable for the whole application is $GLOBALS['mm']. This has the effect of loosening the coupling of disparate parts of the application. A better approach than what I've showed, is to have specific management classes for dbc and user so that proper encapsulation can occur. This would require that $GLOBALS['mm'] have a way to retrieve the manager rather than have methods to return the objects. This is how InterJinn does things; however, InterJinn has the added advantage of providing a base class to extend for components and services that itself provides a method which interfaces to the dynamic loader (middle man). For instance in components or services written in InterJinn the following illustrates the simplicity of the scheme: $dbmanager = $this->getService( 'dbManager' ); $dbc = $dbmanager->do->getConnection( 'dbKeyword' ); $dbc->do->query( 'blah blah blah' ); $dbc->do->free(); Additionally since it was designed this way from the ground up, access to all internal services just like the database follow the same convention: $sessionManager = $this->getService( 'sessionManager' ); $session = $sessionManager->do->getCurrentSession(); echo 'User Id: '.$session->getData( 'userId' ); The above would almost never be used, since the property aspect of the framework allows for transparent binding of session fields to the component or service object itself. So a property would be declared for the component's property path, and then the following would be used instead: echo $this->userId; Just to tout the further advantages, InterJinn's service architecture requires that services are registered. This means that the service code is only loaded when it is requested and that by changing the registration you can completely override the service with your own cooked or from scratch version without ever modifying the core code. This means when you upgrade, you have no need to port your changes over to the core. Anyways hope I've been informative. Also you never need to include the code yourself, the registration indicates to the dynamic loader where to find the code. This means less mucking with includes and more portability from one location to another (though the php.ini include path can em,ulate this, though personally I don't like the include_path). Cheers, Rob. -- .------------------------------------------------------------. | InterJinn Application Framework - http://www.interjinn.com | :------------------------------------------------------------: | An application and templating framework for PHP. Boasting | | a powerful, scalable system for accessing system services | | such as forms, properties, sessions, and caches. InterJinn | | also provides an extremely flexible architecture for | | creating re-usable components quickly and easily. | `------------------------------------------------------------' -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php