Tag: programming
PHP Class Tips
We're starting to use OO in our PHP at work. I discovered when I started using it why I'd been having problems wrapping my head around some of the applications I've been programming lately: I've become accustomed in Perl to using an OO framework. Suddenly, programming in PHP was much easier.
There's a few things that are different, however. It appears that you cannot pass objects in object attributes, and then reference them like thus:
$object->db>query($sql)
PHP doesn't like that kind of syntax (at least not in versions 4.x). Instead, you have to pass a reference to the object in the attribute, then set a temporary variable to that reference whenever you wish to use it:
$object->db =& $db;
...
$db = $object->db;
$res = $db->query($sql);
What if you want to inherit from another class and extend one of the methods? In
other words, you want to use the method from the parent class, but you want to
do some additional items with it? Simple: use parent
:
function method1()
{
/* do some pre-processing */
parent::method1(); // Do the parent's version of the method
/* do some more stuff here */
}
Update:
Actually, you can reference objects when they are attributes of another object; you just have to define the references in the correct order:
$db =& DB::connect('dsn');
$this->db =& $db;
...
$res = $this->db->query($sql);
I've tested the above syntax with both PEAR's DB and with Smarty, and it works without issue.
HTML::FillInForm
The CGI::Application::ValidateRM
module utilizes HTML::FillInForm
to fill in
values in the form if portions did not pass validation. Basically, it utilizes
HTML::Parser
to go through and find the elements and match them to values.
It's used because the assumption is that you've built your form into an
HTML::Template
, and that way you don't need to put in program logic into the
form.
Seems another good candidate for using FillInForm
would be to populate a form
with values grabbed from a database… I should look into that as well!
HTML::Template notes
I've used HTML::Template
a little, mainly in the Secret Santa project I did
this past Christmas for my wife's family. One thing I disliked was using the
normal syntax: <TMPL_VAR NAME=IMAGE_SRC>
— it made looking at it difficult (it
wasn't always easy to tell what was an HTML tag, what was plain text, and what
was HTML::Template
stuff), and it made it impossible to validate my pages
before they had data.
Fortunately, there's an alternate syntax: wrap the syntax in HTML comments:
<!-- TMPL_VAR NAME=IMAGE_SRC -->
does the job. It uses more characters, true,
but it gets highlighted different than HTML tags, as well, and that's worth a
lot.
And why do I have to say "NAME=" every time? That gets annoying. As it turns
out, I can simply say: <!-- TMPL_VAR IMAGE_SRC -->
, and that, too will get the
job done.
Finally, what about those times when I want to define a template, but have it
broken into parts, too? Basically, I want HTML::Template
to behave a little
like SSI. No worries; there's a TMPL_INCLUDE
tag that can do this: <!-- TMPL_INCLUDE NAME="filename.tmpl" -->
.
CGI::Application::ValidateRM and Data::FormValidator
I've been reading a lot of posts lately on the CGI::App
mailing list about using
CGI::Application::ValidateRM
(RM == Run Mode); I finally went and checked it
out.
CGI::App::ValRM
uses Data::FormValidator
in order to do its magic.
Interestingly, D::FV
is built much like how I've buit our formHandlers
library at work — you specify a list of required fields, and a list of fields
that need to be validated against criteria, then provide the criteria. It goes
exactly how I would have done our libraries had we been working in perl —
supplying the constraint as a regexp or anonymous sub in a hashref for the
field.
Anyways, it looks like the combination of CGI::App::ValRM
with CGI::App
could greatly simplify any form validations I need to do on the site, which will
in turn make me very happy!
Design Ideas
I had some success last night with the My::Portal
CGI::Application
superclass I'm building — I actually got it working with CGI::Wiki::Simple
(after I debugged the latter to fix some delegation issues!). Now that I know the "proof-of-concept" works, I'm ready to start in on some other issues.
The first issue is: how can I specify different directories for different applications to search for templates, while retaining the default directory so that the superclass can build the final page? I could always simply keep all templates in a single directory and simply prefix them, but that seems inelegant, somehow. I'll need to explore how HTML::Template integration works with CGI::App.
Second, and closely related: how do I want it to look, in the end? I could see keeping the design we have — it's clean, simple, and yet somehow functionally elegant. Okay, I'm exaggerating — it's your standard three-column with header and footer. But it goes with the idea of blocks of content. I need to think about that.
I saw a design idea for a WikiWikiWeb today, though, that totally changed my ideas of how a Wiki should look. I hadn't been to Wikipedia for some time, but a Google link to Gaston Julia showed up on Slashdot as it shut down a site in Australia, and so I visited it. I like the new design — it separates out the common links needed into a nice left menu, and puts a subset of that at the top and bottom of the main column as well, using nice borders to visually separate things. I much prefer it to PhpWiki's default style, as well as to anything else I've really seen so far relating to Wiki layout.
More CGI::App research... Try the manual!
So, I'm a bit of an idiot… it's been so long since I looked at CGI::App
, and
yet I felt I had such a grasp on it, that I overlooked the obvious step: look
at the manual!
In particular, there's a whole series of methods that are used to tailor
CGI:App
to your particular needs, and these include cgiapp_init()
,
cgiapp_prerun()
, and cgiapp_postrun()
.
-
cgiapp_init() is used to perform application specific initialization
behaviour, and is called immediately before the
setup()
method. It can be used to load settings from elsewhere; if it were called only from a superclass from which other modules inherited, it would then provide common settings for all modules. -
cgiapp_prerun() is called immediately before the selected run-mode. If it
were called only by your superclass, you could perform items such as
authorization or even form validation; this would then be standard for all
your applications. (You can use the
$self->prerun_mode('mode')
call to to override the selected run-mode, for instance, thus allowing you to redirect to a different mode if a user isn't permitted there.) - cgiapp_postrun() is called after the run-mode has returned its output, but before http headers have been generated or anything sent to the web browser. Again, if defined in a superclass, it means that you could then place the run-mode output in a specific place within a larger template, and even call other routines to fill in other parts of the main template. You could even check to see if certain parameters were passed to the page, and change the type of output you send back (XML, PDF, image, etc.), allowing you to have a common query element that changes the output type (e.g., a 'print' parameter that returns a PDF or a stripped down template).
In addition, you could specify in the superclass that you're using
CGI::Simple
for the query object (using the cgiapp_get_query
method), or
you could rewrite the load_tmpl()
method to use Template::Toolkit
or some
other templating system, etc.
Doesn't look so crazy anymore…
CGI::Application Research
I've been wanting to redevelop my home website for some time using
CGI::Application
. The last time I rewrote it from PHP to perl, I developed
something that was basically a subset of the things CGI::App
does, and those
things weren't done nearly as well.
The problem I've been running into has to do with having sidebar content, and
wanting to run basically a variety of applications. I want to have a
WikiWikiWeb, a photo gallery, some mail forms, and an article database/blog;
CGI::App
-based modules for each of these all exist. But I want them all to
utilize the same sidebar content, as well — and that sidebar content may vary
based on the user.
My interest got sparked by this node on
Perl Monks. The author tells of an acquaintance who goes
by the rule that a CGI::App
should have 10-12 states at most; more than that,
and you need to either break it apart or rethink your design. And all CGI::App
s
inherit from a common superclass, so that they share the same DB connections,
templates, etc.
So, I've been investigating this problem. One node on PM
notes that his ISP uses CGI::App
with hundreds of run modes spread across
many applications; they created a module for session management and access
control that calls use base CGI::Application
; each aplication then calls
use base Control
, and they all automatically have that same session
management and access, as well as CGI::Application
.
Another node mentions the
same thing, but gives a little more detail. That author writes a module per
application, each inheriting from a super class: UserManager.pm
, Survey.pm
,
RSS.pm
, Search.pm
, etc. You create an API for that super class, and each
CGI::App
utilizes that API to do its work.
This also seems to be the idea behind CheesePizza,
a CGI::App
-based framework for building applications. (All pizzas start out
as cheese pizzas; you simply add ingredients.) The problem with that, though,
is that I have to learn another framework on top of CGI::App
, instead of
intuiting my own.
But how do I write the superclass? Going back to the original node that sparked
my interest, I found a later reply that described how you
do this. The big key is that you override the print
method — this allows you
to customize the output, and from here you could call functions that create
your sidebar blocks, and output the content of the CGI::App
you just called in
a main content area of your template.
Grist for the mill…
robots.txt
One thing I've wondered about is the syntax of the robots.txt
file, where it's
placed, and how it's used. I've known that it is used to block spiders from
accessing your site, but that's about it. I've had to look into it recently
because we're offering free memberships at work, and we don't want them indexed
by search engines. I've also wondered how we can exclude certain areas, such as
where we collate our site statistics, from these engines.
As it turns out, it's really dead simple. Simply create a robots.txt
file in
your htmlroot, and the syntax is as follows:
User-agent: *
Disallow: /path/
Disallow: /path/to/file
The User-agent
can specify specific agents or the wildcard; there are so many
spiders out there, it's probably safest to simply disallow all of them. The
Disallow
line should have only one path or name, but you can have multiple
Disallow
lines, so you can exclude any number of paths or files.