> 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

Reply via email to