p2p.wrox.com Forums

Need to download code?

View our list of code downloads.


  Return to Index  

beginning_php thread: the separation of SQL calls from HTML formatting


Message #1 by "Lawrence" <spam@k...> on Fri, 7 Feb 2003 00:16:33 -0500
Nik,

Last year you wrote a ton of good stuff about how functions should never fetch content and then output it as HTML.
Separate functions should fetch the content, and some other function should out put it.

I'm wondering if you're advice still holds for objects. I'm rewriting my old software as OO. Is it alright to have
one class grab content from the database, format it, and then output it, so long as different methods do the
different things? Or is a crime against good design?

=+= sapereAude






Message #2 by "David Scott-Bigsby" <DScott-Bigsby@P...> on Fri, 7 Feb 2003 13:23:44 -0800
> Nik,
>
> Last year you wrote a ton of good stuff about how functions
> should never fetch content and then output it as HTML.
> Separate functions should fetch the content, and some other
> function should out put it.
>
> I'm wondering if you're advice still holds for objects. I'm
> rewriting my old software as OO. Is it alright to have
> one class grab content from the database, format it, and then
> output it, so long as different methods do the
> different things? Or is a crime against good design?

No doubt Nik will answer this, but since I got to it first...

Yes, the same holds true. Seperating presentation, business logic and 
data storage is considered best practice architecture for good reason -- 
any one of those things may change, and you want to isolate the work 
you're going to do to limit unexpected effects of your changes.

For example, say you switch databases. Instead of going through all your 
code to change the database access code, wouldn't it be nice if it was 
all in one neat little object, and the rest of the code was unaffected 
by the changes? Using a class to encapsulate your database does this -- 
your business logic calls a Data object with commands like 
Data.AddContact() and doesn't care what the Data object does with it so 
long as Data.GetContact() gives the correct stuff back.

Another example: You've got code that makes rockin' HTML, then the boss 
says it's time to support browsers on PDAs -- with their tiny wee 
screens. Wouldn't it be nice if you could just write a second library of 
presentation code that easily reuses the business logic and data 
handling of your current system? That is, a user request comes in, and 
your code determines the user's browser, platform etc. from the HTTP 
headers and then chooses to use either your (a.) standard interface code 
library or your (b.) PDA interface code library -- either of which may 
be a class -- but both of these use the same business logic module (or 
class) which uses the same data module (or class).

Just a thought.

dsb

***************************************       
David Scott-Bigsby
Product Manager, Web Site and PEDN

PureEdge Solutions
The Leader in Secure XML e-Forms

v:250-708-8145  f:250-708-8010
1-888-517-2675   www.PureEdge.com
***************************************

Message #3 by "Nikolai Devereaux" <yomama@u...> on Fri, 7 Feb 2003 13:57:42 -0800
> Last year you wrote a ton of good stuff about how functions should
> never fetch content and then output it as HTML.
> Separate functions should fetch the content, and some other
> function should out put it.
>
> I'm wondering if you're advice still holds for objects. I'm
> rewriting my old software as OO. Is it alright to have
> one class grab content from the database, format it, and then
> output it, so long as different methods do the
> different things? Or is a crime against good design?


Hi Lawrence,

First of all, thanks for the compliment, I appreciate it.


Well, it really depends, I guess.  What are you objects writing?

A lot of people, when first starting out with objects, simply create an object
to wrap each database table.  This is fine and dandy, but sometimes I think
they take it too far, and have that object be in charge of outputting a lot of
content to the client.

The problem is that much of your code within an object is repeated across all
objects.  If you have tables and/or forms, you can easily create objects to
handle all the repetitive stuff there.

Your database wrapper object will handle inserting, updating, selecting, and
removing items from the database.

Your form objects can also be written to handle form input validation, things
like that.

I still believe that no objects or functions should ever output anything to
the client.  That should be the job of the main script.  The output strings
can be generated and created within functions (or objects), but those strings
should be returned to the main script which can store it in a variable or echo
it directly.


Hope this makes sense!

Nik

Message #4 by "Lawrence" <spam@k...> on Sat, 8 Feb 2003 00:04:11 -0500
>A lot of people, when first starting out with objects, simply create an object
>to wrap each database table.  This is fine and dandy, but sometimes I think
>they take it too far, and have that object be in charge of outputting a lot of
>content to the client.

I did something like this last year when I first wrote the software. I had a separate file for each table in the
database, and each file had functions that handled the inserts, selects, updates, and deletes for that table.




> The problem is that much of your code within an object is repeated across all
> objects.  If you have tables and/or forms, you can easily create objects to
> handle all the repetitive stuff there.

Yes, that is exactly the trouble I've noticed. The repetition is rather great. I'd like to avoid it.




> I still believe that no objects or functions should ever output anything to
> the client.  That should be the job of the main script.  The output strings
> can be generated and created within functions (or objects), but those strings
> should be returned to the main script which can store it in a variable or echo
> it directly.

I've thought of this, and my one concern is that it slows down the moment the user gets their web page delivered.
I've thought that maybe the main page should turn output buffering on, gather all the content, format it, and then
turn output buffering off, allowing it all out to the end user. The reason I'm afraid of doing this is that it
forces the user to wait for the last, slowest call to the database. After all, a page has several elements, stored
in different tables - there are the navigation elements, the main article, perhaps comments appended to the end.

You once said you kept all your database calls in their own file, like stored procedures. Could you elaborate on
that?



It would be great if Wrox had a better search engine, or if you had all your posts in one place, so that I could
more easily find some of your old posts. I went searching for the example log software you did that demonstrated
your technique of separating sql and html, but didn't find it.


take care,


lawrence


Message #5 by Kyle Ketterer <BIGE88FAN@c...> on Sat, 08 Feb 2003 00:08:04 -0800
Originally Posted By Nik:
>>I still believe that no objects or functions should ever output
anything >>to
>>the client.  That should be the job of the main script.  The output
>>strings
>>can be generated and created within functions (or objects), but those
>>strings
>>should be returned to the main script which can store it in a variable
or >>echo
>>it directly.

I also agree. But on contrast, I will use the commercial script
"vBulletin" as an example. I have looked at the code in their script,
and they do not output the data directly in the main script. I suppose
as you get more complex with different functions and such, you simply
can't just output the data in the main script. For instance, vBulletin's
output scheme is based on functions. They have templates for each area
of their script stored in the database, the script then uses a function
to get that certain template, and they simply eval() it as php, and echo
it out. I believe they have probably the fastest MySQL driven forum out
there, and that's pretty much how their output of data is done.

I am myself still learning some more advanced concepts of PHP, but I
have come pretty far and learned a lot just by reading this book and
discussing over these forums. I am still looking for a lot of advice, so
I'll just ask this simple question. 

What's the harm in outputting data through a function? Are there any
real slow downs that will occur during execution of a script?

Thanks a lot,

-Kyle-


Message #6 by "Lawrence" <spam@k...> on Sat, 8 Feb 2003 00:52:01 -0500
> For example, say you switch databases. Instead of going through all your code to change the
database access code,
>wouldn't it be nice if it was all in one neat little object, and the rest of the code was unaffected by the
changes? Using a
>class to encapsulate your database does this -- your business logic calls a Data object with commands like
>Data.AddContact() and doesn't care what the Data object does with it so long as Data.GetContact() gives the
correct
>stuff back.

That's interesting. So object Data has a method that's focused on returning Contacts? And also a method for getting
AccountInfo? And also a method for getting AlterationHistory? I've built a small content management system, with 8
tables, one for navigation, one for the template, one for users, one for comments, one for articles, etc. Do I put
every single Select statement into one object? The way I did it before, basically, each table had its own set of
select, insert, update, and delete functions - which is what I'm trying to get away from, but I'm not sure what I'm
heading toward.

I guess my only concern with putting every Select statement into one object would be that it would be a huge
object.

Do I have a separate object for Deletes, Updates, and Inserts, or do they all go in the same object as Select? I'm
simply asking how you would do it.





> Another example: You've got code that makes rockin' HTML, then the boss says it's time to support browsers on
>PDAs -- with their tiny wee screens. Wouldn't it be nice if you could just write a second library of presentation
code
>that easily reuses the business logic and data handling of your current system? That is, a user request comes in,
and
>your code determines the user's browser, platform etc. from the HTTP headers and then chooses to use either your
>(a.) standard interface code library or your (b.) PDA interface code library -- either of which may be a class --
but
>both of these use the same business logic module (or class) which uses the same data module (or class).

I understand the point you're trying to make here, but this doesn't seem as dependent on objects as your last
example. In my software the content is already kept separate from the template. Templates have their own table in
the database. The content - the text that makes up the articles, is stored separate. Formatting output to a PDA is
mostly about using a different template - or leaving it out and just streaming pure text to the PDA. The only hang
up would the images still embedded in the articles.

But that does bring me to the next issue, which is presentation. In the first version of the software, there were a
lot of echo statements that sent stuff straight to the browser. For a variety of reasons I'd like to have more
control over the output. Does that imply having an object whose only task is formatting output?

The CMS I've done gets by, for the most part, with just one variable being passed in the query string, that being
pageId.

So I guess the way I'm envisioning the next version of the software, the index page receives a request, then
launches the db object that connects to the database (version 1 already had a db object, borrowed from a co-worker,
that handled connectivity), then invokes another object to make the select calls, then gets everything - the
template, navigation, article and comments associated with that pageId, then hands the return to an object that
does nothing but format the output, which then turns off output buffering and lets it all go to the screen?


This is what I have on my index page right now, in version 1:

<?php
include("atp/mcIncludes/mcBaseFunctions.php"); //contains basefunctions, such as getNeededFiles
getNeededFiles($needed); //this gets all the other files
extract($config = getConfig()); //everything is the config file is stored in an array called $config
$db = new CMySQL($db_persistent, $db_database, $db_server, $db_user, $db_password, $db_port);
$users_online = countUsers();

showPage();
sendMail();
?>

This is the whole page. Basically, all the real work is done by showPage(), which gets the template. The template
is PHP code, but mostly its a bunch of echo statements with just a few functions. The template get puts through
eval() so the PHP executes. Somewhere in that template they'll be the function showNav() which will fetch the
navigation elements and display them (two functions, actually, not one) and then somewhere else in that template
they'll be the function showMainContent(), which will fetch the main article out of the database and display it.

This is, I realize now, kind of a primitive system. One thing is there are many, many calls to the database - at
least 7 per page. Some of those don't matter so much - it doesn't matter if the request for the comments is slow
because the user will be reading the main article for awhile.

Anyway, I guess I'm now thinking the index page should look more like this: (pseudo code):


<?php
//object contains utilitarian code that does stuff like include all the other files,
include("base.php");
$base = new mcBase();
//class with code for users, on creation it does stuff like count how many people
//are visiting the site, which would replace countUsers() above, see what the visitors current
//logged status is
$users = new mcUsers();
// establish a connection to the database
$db = new CMySQL($db_persistent, $db_database, $db_server, $db_user, $db_password, $db_port);
// class takes the $pageId variable and uses it to do selects, getting all that's needed from the db
$fetchedPage = new mcFetchPage();
// results get turned over for processing
$processedPage = new mcFormat();
$processedPage->format($fetchedPage);
// this final could do stuff like make sure mail gets sent, when that is appropriate.
//Should email class be invoked from inside of base, or up here on this level?
$base->end();
?>



Or maybe instead of this:

$processedPage = new mcFormat();
$processedPage->format($fetchedPage);

this:

$processedPage = new mcFormat($fetchedPage);


I'm in the dark so tell me what you would do please.

thanks again.

--lk




Message #7 by "David Scott-Bigsby" <DScott-Bigsby@P...> on Sun, 9 Feb 2003 21:32:41 -0800





[beginning_php] RE: the separation of SQL calls from HTML formatting


<Lawrence>> For example, say you switch 
databases. Instead of going through all your code to change the database access 
code,>wouldn't it be nice if it was all in one neat little object, and 
the rest of the code was unaffected by thechanges? Using a>class to 
encapsulate your database does this -- your business logic calls a Data object 
with commands like>Data.AddContact() and doesn't care what the Data 
object does with it so long as Data.GetContact() gives 
thecorrect>stuff back.That's interesting. So object Data has 
a method that's focused on returning Contacts? And also a method for 
gettingAccountInfo? And also a method for getting AlterationHistory? I've 
built a small content management system, with 8tables, one for navigation, 
one for the template, one for users, one for comments, one for articles, etc. Do 
I putevery single Select statement into one object? The way I did it before, 
basically, each table had its own set ofselect, insert, update, and delete 
functions - which is what I'm trying to get away from, but I'm not sure what 
I'mheading toward.</Lawrence>
I actually use libraries of functions rather than classes -- 
my scripts don't last long enough to hold state information, and PHP doesn't 
have the concept of "private" information within classes, so I don't see the 
point in using them. (For my VB apps, it's a different story...)
I have a MYSQL library, which handles the functions to INSERT, 
DELETE, etc., and has a few others for constructing standard SQL statements. 
Another library (one that's a tad big, I think) has the "AddContact"-type 
functions. The difference is that while the MYSQL library is handy for any 
application accessing any MYSQL database, the second one understands the 
business rules (e.g., minimum data for a contact) and handles blocks of 
information more complex than a single table (e.g., the info passed to 
AddContact might get inserted into several related tables). There isn't a strict 
split between knowledge of the MYSQL and the business logic -- the business 
library uses mysql_* functions -- but none of the scripts that call the business 
functions have a clue what database they use. Should I port the site to, say, MS 
SQL Server, these are the two scripts I'd have to 
change.<Lawrence>I guess my only concern with putting every 
Select statement into one object would be that it would be a 
hugeobject.Do I have a separate object for Deletes, 
Updates, and Inserts, or do they all go in the same object as Select? 
I'msimply asking how you would do it.</Lawrence>Other than 
the general advice to seperate data, business and presentation (advice I mostly 
follow myself) I really can't offer you a template. As far as I can tell, 
determining the best object model for a particular app (much less all apps) is 
still more art than science. You may want to look into the various "patterns" 
books for software design. They take the view that the same types of problems 
occur again and again, and do proffer "best practices" OO solutions.
HTHs,
dsb



Message #8 by "Nikolai Devereaux" <yomama@u...> on Tue, 11 Feb 2003 13:26:45 -0800
nik> I still believe that no objects or functions should ever
nik> output anything to the client.  That should be the job of
nik> the main script.  The output strings can be generated and
nik> created within functions (or objects), but those strings
nik> should be returned to the main script which can store it
nik> in a variable or echo it directly.

kyle> I also agree. But on contrast, I will use the commercial script
kyle> "vBulletin" as an example. I have looked at the code in their script,
kyle>
kyle>   <snip>
kyle>
kyle> What's the harm in outputting data through a function? Are there any
kyle> real slow downs that will occur during execution of a script?

Actually, you're probably going to notice more of an efficiency problem my
way -- storing strings and concatenating them into continually larger strings
can be a huge problem if it's not done well.

Consider this:

$names = array('nik', 'lawrence', 'kyle', 'jake', 'peter', 'john');

$greeting = "Hello";

foreach($names as $name)
{
   $greeting .= ", $name";
}

That's a lot of appending.  Each iteration of the loop, PHP finds the end of
the $greeting string, and appends ", $name" to it.


For a low to medium traffic site, I think that the benefit of having really
clear and concise code outweighs the extra processing time.

Also, it's definitely possible to rewrite inefficient code (like that above)
more efficiently.

$greeting = "Hello" . join(", ", $names); // for example =)


Take care,

Nik

Message #9 by "Nikolai Devereaux" <yomama@u...> on Tue, 11 Feb 2003 13:44:44 -0800
I'm sorry I haven't had the time to write a much more detailed response.

> I guess my only concern with putting every Select statement into
> one object would be that it would be a huge
> object.
>
> Do I have a separate object for Deletes, Updates, and Inserts, or
> do they all go in the same object as Select? I'm
> simply asking how you would do it.


Basically, you don't have to store all your SELECT queries in an object; you
can generate most similar queries (be they SELECT, INSERT, DELETE, whatever)
just as you do HTML.


Say you had a Person object that wrapped a database table.  That Person object
shouldn't really have anything to do with the HTML generated anywhere else in
the site.

I remember posting a table very similar to this once:

                Outputs anything    Makes DB calls    Generates HTML
main script:          yes                 no                no
SQL functions:         no                yes                no
FORM utilities:        no                 no               yes


The same holds true (imho) for objects; rather, instead of having one or more
libraries of SQL functions, you organize them into Objects instead.


Let's say you had a users table.  Each row in the users table is a user.

TABLE:  users
id
username
password


class User
{
   var $id;
   var $username;
   var $password;

   function User($id, $un, $pw)
   {
      $this->id       = $id;
      $this->username = $un;
      $this->password = $pw;
   }

   function get_id()       { return $this->id;       }
   function get_username() { return $this->username; }
   function get_password() { return $this->password; }
};


// This class wraps the users table and provides pseudo-stored
// procedures to interact with that table.
class Users
{
    function addUser($user) // $user is a User object
    {
        $query = "INSERT INTO users ('username', 'password') "
               . "VALUES ('" $user->get_username() . "', "
               .         "'" $user->get_password() . "')";
        return db_query($query);
    }

    function getUserByName($username)
    {
        $query = "SELECT id, username, password FROM users "
               . "WHERE username = {$username}";

        $result = db_query($query);

        if ($result && ($row = db_fetch_array($result)))
        {
            return new User($row['id'],
                            $row['username'],
                            $row['password']);
        }

        return false;
    }

};



See, the User and Users classes don't have anything to do with HTML -- they're
only purpuse is to organize information and interface with the database.  That
way, if the database schema changes, or the queries need to change, or
whatever, all you need to do is modify these classes to handle the changes and
the rest of the site will work fine.



Can't spend more time on this now, perhaps later.


Take care,

Nik


  Return to Index