[fpc-pascal] The new book: "WEB and database programming with fpc and Lazarus for newbies and professionals"
Burkhard Carstens
fpc at bcsoft.de
Wed Jun 16 20:10:09 CEST 2010
.. anybody knows where I can buy it? ;-)
I just started my first web application and .. well .. the basics work,
but I have the feeling, I'm doing it the wrong way.
[Warning: Looong post]
What it's about:
It's a time-punch machine that registers when I'm working on which
project. Data is stored in postgres tables and shall be reported
preferably as nice pdf files per customer listing the projects and the
times spent on them (and off course the money I'd like to have for
that..)
Unfortunately, I'm new to all related topics.:
The only experience in DB programming is about 10 or 12 years ago
(writing this time-punch machine as desktop app in Delphi <= 6). Played
with fpc/laz and postgres a few times since then, but never got
anything working.
There is some knowledge about XML and the concept of DOM but only basic
html stuff and absolutely nothing about css and JavaScript, ajax,
extjs, jQuery, JSON... well, there was nothing when I started a week
ago.
This is my journey so far:
(all done with fpc and lazarus from trunk)
chapter 1 - Database programming
First, I created a desktop app to play with the database. All the DB
components on a DataModule and some DBGrid, DBNavigator on a form.
* First problem:
Data changes in the grid don't get to the database.
* Solution:
in SQLQueryTimes.OnAfterPost add:
SQLQueryTimes.ApplyUpdates;
SQLTransactionTimes.CommitRetaining;
* Next problem:
When doing "insert, post, edit (the inserted row), post" the data
doesn't get to DB.
* Found reason:
The primary key is an auto-increment. It is added by postgres when
inserting the record, but not reported back. Therefore, the following
Update statement uses (probably?) "UPDATE .. WHERE times_id = NULL .."
while times_id actually got a non-NULL value in the DB. So the update
statement does nothing, not even reporting an error.
* Solution:
none. According to http://bugs.freepascal.org/view.php?id=16076 this is
not yet implemented.
* Workaround:
Do a "refresh" after the "insert, post". Downside: The cursor is lost,
i.e. you have to navigate back to the just inserted record before
further editing.
* Next Problem:
The "projects" are stored in a second table with id, name and some other
info. Now I'd like to see (and deal with) the projects name instead of
its ID in the times_grid. Some keywords came to memory: "Master/
Detail", "Lookup" and "JOIN" .. at this point, I decided to order some
books:
"SQL von Kopf bis Fuss" ("Head first SQL"), a funny book, though a
matter of taste whether one likes fun when searching technical
information (I do). Sadly, the examples all refer to mySQL and pretty
often there is a note like "not all RDBMS understand this syntax".. but
still, very helpfull book.
"PostgreSQL", pretty dry admin doku ..
"Lazarus", very nice book, covering loads of topics. While it shed quite
some light into my understanding of the database components, it
unfortunately ends right there where my quest begins .. at least
regarding WEB and DB programming .. hence the topic of this post :-)
* Solution:
none, at least not the way I intended. Seems like DBGrid is not (yet)
able to offer a LookupCombo in a cell like Delphi does. (After I found
out, I also saw the related bug report .. ) I got something working
with a separate DBLookupList next to the grid ..
At this point, I stopped dealing with the desktop GUI and went over to
fpWeb stuff. I just liked the idea of "open dataset, select/insert/
update, close dataset". SELECTing the data using a INNER JOIN statement
did what I need for displaying ... and editing .. well that's still far
away, it seems.
chapter 2 - web programming
Here is what I did and learn so far:
* New/Project/CGI Application, save as "cgitimes"
* Add action "main" (code and template mainly taken from the
"listrecords" cgi example and adapted).
* Add action "switch"
* "main" produces a page with a status like this:
either
| working on {project name}
| click to pause or call it a day (href=switch?NewProjectId=0)
or
| Inactive
| click to continue with {last_active_project_name}
| (href=switch?NewProjectId=last_active_project_id)
and a table:
| .. or switch to a different project:
| project_name (href=switch?NewProjectId=1)
| project_name (href=switch?NewProjectId=2)
...
Now when clicking one of the links, I get to the "switch" page. The
action does to the DB what it should do but I didn't intend to see a
separate page. I only wanted the action to act on DB and refresh the
main page.
So I tried to add a http-equiv="Refresh" content="3,URL=main" to
AResponse.CustomHeaders and went crazy because it didn't work.
Actually, setting any other header stuff (ContentType, ContentEncoding)
also didn't work .. at least it didn't show up on "View document
source" in the browser. ( hey, don't laugh so loud! )
It took me some time to realize that my web module descends from
TSessionHTTPModule and not from any TxxHTMLModule .. so the headers I
tried to change were actally HT*TP* headers and not HT*ML* headers..
This confusion was partly due to the fact that I thought, a HTML
document needs a <head> .. </head> section but none of the templates
got one. So I assumed, this is added automatically...
After this enlightenment, I got further. Just adding a "<head> ..
Refresh .. URL=main ..</head>" via "AResponse.contents.add" did the
job. Still, this didn't look or feel right.
Back to the cgi chapter in Lazarus book, I saw the "Location" field in
the HTTP header and tried setting
"AResponse.Location:=ARequest.Referer;" in the switch action handler.
Heureka! That did the job! Still I don't know, wheter this is the
correct way or not and whether I should return a specific HTTP status
code (201, 205, 302, 303 or 307) ?
Now I want more functionality: edit field to add a note to the current
time_record on main page, a way to add new projects (probably a
separate page?), another page to manipulate the times table in a grid
and of course: reports, reports, reports (Is it possible to use the
LazReport in a cgi)?
So how to proceed? Should I change my FPWebModule to a THTMLModule?
What happens, when I have multiple T[FPWeb,HTML]Modules in my cgi? Now I
call it with http://myhost/cgi-bin/cgitimes/main (or even without the
"main"). With multiple modules, I'd need to select the module like
http://myhost/cgi-bin/cgitime/MODULE_1/main ?
After installing the lazwebextra package, there are lots of components
(THTMLxxxProducers, TxxWebDataYY) .. well, precisely, there are 21
components on the fpWeb page + 5 different DataModules in
file/new/module ... how are those supposed to gear into each other?
which components must be placed on what kind of module?
Looking at the fpWeb examples as well as the webdesign package from
Joost (which installs another DataModule + countless components), I
realized that both use some JavaScript lib, namely "ExtJS" and
"jQuery". So it seems, a decent interface can only be done using
JavaScript. Ok .. I usually have this turned off in my browser but I'm
willing to change my mind on this.
On a first glance, ExtJS looks somewhat cooler, but it's GPL licensed.
Does that mean, I need to release the source of my cgi program, if I
decided to distribute it? While it is irrelevant for this (in-house,
toy) project, I'd prefer to learn the "right" one, i.e. the one I can
also use in comercial closed source projects.
After spending hours on www.w3c.org and www.w3schools.com, extjs.com
(now sencha.com) and jquery.com reading a lot about html, dhtml,
javascript and checking out some docs and examples about extjs and
jquery, I got the feeling that all these pieces could form a nice
picture .. just I still couldn't see it.
Then I found this artice and now all of the sudden, everything makes a
lot more sense:
http://www.ibm.com/developerworks/web/library/wa-ajaxintro1.html
Guess, it might be good to start from ground up (now that I found
ground):
Make some nice html files with some JavaScript functions, which just
"call" my cgi via XmlHTTPRequest to insert something into the DB or
return some results or tiny html snippets.
Any hints and suggestions are welcome!
Writing this mail helped me to clean up my mind. I could have deleted it
after writing, but I thought, it probably helps some other newbie
and/or maybe motivates someone (Michael, Joost ?) to start writing "the
new book" ;-)
However, thanks for another great toolset: fpWeb ! It looks really
promising.
Best regards
Burkhard
More information about the fpc-pascal
mailing list