The need of web application framework for fpWeb
lazarus / 7-LCL
----------------------------------------------------------------------
Leledumbo · 2010-10-18 03:17
These days, in business world web applications rule. And usually I
create those web apps using PHP because it has a lot of good
frameworks. Lazarus and FPC already have underlying libraries to
create web applications, but we miss frameworks. fpWeb have templates,
but it's too limited.
First, it can't handle php (lua already does this as well) style web
pages where code (though maybe just echo's and foreach's) are mixed
with HTML. From fpWeb samples, for instance, if data needs to be
displayed in a table, the logic unit should take the row template and
replace marked symbols with correct values. This, though not deeply,
violates MVC rule where logic should be separated from view. It's
better just to pass the value in data structure form to the view and
let the view decides how to display the data.
Next, it can't handle inheritance or nested templates. Typical web
applications would have title header and navigation menu written for
most of its pages, using nested templates, code redundancy for things
like this could be eliminated. Even more, nested templates could be
used for non-visual elements, such as doctype-html-head-body
declarations.
I usually have a base view containing:
Code: [Select]
$type) echo HTML::style($file
, array('media' => $type)), "\n" ?>
where $title, $styles, $scripts, and $content can be filled or
extended by its descendants.
That saves a lot of code, and creates a very extensible and reusable
code. What do you think?
----------------------------------------------------------------------
bobo · 2010-10-18 05:35
I don't think the fptemplate (template handling of fpweb) is as
limited as you say.
You can have any code in your templates, it will still work,
especially because you can specify the tag start, tag end, tag param
start, tag param end, tag value separator strings dynamically on the
fly before calling the tag replacements. In fact, these were
implemented exactly for the reason that Delphi had the limitations you
have mentioned.
I am not sure what you mean exactly by nested templates, but I think
you can do those too. Just reconfigure the above parameters and call
the replacing again. You can do includes within templates and within
template tag handling you can load in additional templates and do
those again. It is quite flexible.
For example, you can specify a template include file as a tag
parameter, handle it in the tag handling event using the file name
passed, and what you want is done /if I understood what you want
correctly /.
Some info on templates can be found in ...fpc.../packages/fcl-
base/texts/fptemplate.txt
and some demos are in ...lazarus/components/fpweb/demo/fptemplate/*.*
Also, fpweb can now handle the Extjs framework to be the back-end
server side handler for the nice Extjs GUI clients.
Examples on how ExtJS looks like in the browsers:
http://www.sencha.com/products/js/
http://dev.sencha.com/deploy/dev/examples/
----------------------------------------------------------------------
Leledumbo · 2010-10-18 07:00
QuoteYou can have any code in your templatesOK, do we have something
like this:
Code: [Select]
| No. |
Name |
Age |
$person): ?>
|
|
|
QuoteI am not sure what you mean exactly by nested templatesNot
exactly nested template, actually. See it this way, in a traditional
MVC, each controller handles one view. If that controller is extended
by another, then rendering action of the base controller will get
called followed by descendant one.
QuoteYou can do includes within templates and within template tag
handling you can load in additional templates and do those
again.Well... hmm... OK, what about the variables?
I can't explain this template based paradigm very well. So, perhaps if
you will, you can check out this.
----------------------------------------------------------------------
bobo · 2010-10-18 16:21
This became a "little bit long", sorry about that... have too much
time on my hand it seems...
Yes, it seems what you currently use is totally php based.
This means that everything is handled by php include files basically.
With php the code and display functionality is never really separated.
Obviously, you can not mix the fpweb templates with your php code
because there can be only one handler on the web server for a request,
and we can not ask php to process a request and then call fpweb to
process
it again for template tags.
We need to choose which one to use.
The example you list is basically the same example as demonstrated in
...lazarus/components/fpweb/demo/fptemplate/listrecords/...
That is a very basic demo that can be made more complex (ex: instead
of a full record replace with one tag, it can be every field made a
tag,
with format strings passed as tag parameters, etc.)
Taking your example, with fpweb it would look something like this:
Code: [Select]
| No. |
Name |
Age |
{+PERSONS
[-ONEROW=
| ~no |
~name |
~age |
-]
+}
and a call for the fpweb cgi/fcgi/apache_module with the parameters
and variables
is needed to find the needed record(s).
For example ...mywebserver.com/cgi-
bin/myfpwebcgi.cgi/listpersons?recordidlist=blah
would return with the full html response page loading and processing
the above
template and replacing the template tag "PERSONS" with the field
values
(~no, ~name and ~age) for every record requested.
Inside the fpweb "listpersons" action event handler on the server
side, the pascal
code would be something like:
Code: [Select].
.
onerow := TagParams.Values['ONEROW'];//template for 1 row
while not SQLQuery.EOF do
begin
ReplaceText := ReplaceText +
StringReplace(StringReplace(StringReplace(onerow
,'~no', SQLQuery.Fields[0].AsString, [])
,'~name', SQLQuery.Fields[1].AsString, [])
,'~age', SQLQuery.Fields[2].AsString, []) +
#13#10;
SQLQuery.Next;
end;
.
.
It is basically the same thing both with php or fpweb templates.
Except with php,
there is the overhead of the php interpreter while with fpweb there is
only parsing
for the template tags. Also the programming is really on the fpweb
side while the
html template is just really a screen html template with no code in
it.
You can also use frames or IFRAME includes within a template to pull
additional
parts of the html page with separate requests from the server,
processing additional
templates, infinitely. Or just create tags with tag parameters that
helps you create
the response from multiple templates based on the passed parameters.
This way is the way to program web applications when you really want
to have all
control both on the browser and server side. Takes much longer to
develop a web app
(at least the 1st time) because it is low abstraction level html
generation, but you
really have the possibility to micro-manage and customize everything.
The other way is to use some kind of client side framework for the
gui, and use
fpweb only for back-end processing and data providing (like using the
Extjs framework
for gui for example).
Both can be done with FPC/Lazarus easily.
AB
PS: As for variables, there are no variables in fpweb templates,
because there are no
code to interpret and execute in them. Templates are REALLY only for
the html look and
feel.
The code and the variables are inside the fpweb request handler pascal
code on the
server side. There are only request parameters that can be passed from
the browser as
part of the URL or as html form field values.
----------------------------------------------------------------------
Leledumbo · 2010-10-19 02:34
QuoteYes, it seems what you currently use is totally php based.
This means that everything is handled by php include files basically.
With php the code and display functionality is never really separated.
Obviously, you can not mix the fpweb templates with your php code
because there can be only one handler on the web server for a request,
and we can not ask php to process a request and then call fpweb to
process
it again for template tags.
We need to choose which one to use.
No, no, no. I'm just explaining from php side, which I've ever worked
with, and looking for how to implement that in Object Pascal.
QuoteTaking your example, with fpweb it would look something like
this:Exactly.
QuoteIt is basically the same thing both with php or fpweb
templates.Not really. In fpWeb, I need to use StringReplace
explicitly. While in my PHP framework, the variables can be assigned
to the template. The Object Pascal way (that I'm wishing for) perhaps
looks like this:
Code: [Select]AView := TMyView.Create('View filename');
AView['no'] := SQLQuery.Fields[0].AsString;
AView['name'] := SQLQuery.Fields[1].AsString;
AView['age'] := SQLQuery.Fields[2].AsString;
Response := AView.Content;
QuoteAs for variables, there are no variables in fpweb templates,
because there are no
code to interpret and execute in them. Templates are REALLY only for
the html look and
feel.After re-thinking about it, I guess this is not a limitation.
Instead it's a good way to enforce separation between logic and
presentation. So, only previous issue left as my problem.
----------------------------------------------------------------------
bobo · 2010-10-19 05:51
But php does the same "replacestrings", we just do not see it
Plus you can do it in other ways, no need to use StringReplace
exclusively. It can be anything (FORMAT instruction for example if
that is easier for the developer, or a TStringList and then using the
TStringList.Text as replacetext if all records are added, etc.), the
important thing is that at the end of the tag replacement, we have the
string we want the tag to be replaced with in the response.
Taking your "wish" example, you can make that even simpler with fpweb.
In the template tag handler for all database fields you can use one
single
ReplaceText := SQLQuery.FieldByName(TagString).AsString;
you do not even need to check for tag string matches. The only
restriction is, that in the template for all fields coming from the
sql query you need use the same tag name as the field name in the
table.
Code: [Select]
| No. |
Name |
Age |
| {+ID+} |
{+Name+} |
{+Age+} |
if the table record has these 3 fields (ID, Name, Age), or the sql
query at least returns fields with these names.
Of course, this is only good for template values/fields that are not
need to be listed from a loop (1 record only, basically). For loops
you need some kind of string concatenation to return all records. It
is not different with php, it is just not programmed by us directly.
For multiple records it is also a way to just return the table records
as a javascript array into the web page replacing a single template
tag, and then process them from inside javascript on the client side
to display them. But this brings us back again on doing programming
and data processing on the client side.
This will probably not beat the ExtJS framework as a gui, which is
already freely available to everyone.
Additionally, with fpweb the template designers can pass some
additional parameters to the back end.
For example, a current date/time field on the web page can have a tag
{+DATETIME [-FORMAT=MM/DD/YYYY hh:mm-]+}
which passes the format the screen designer wants the datetime to be
in. No back-end changes are needed if they want to change the format
and in the tag handling we just need to apply the format from the tag
parameter. They just change it in the template, the
CGI/FCGI/Apache_module does not need to be changed. Something like
this can be included for all field types if necessary giving free hand
to the screen designers.
AB
----------------------------------------------------------------------
Leledumbo · 2010-10-19 06:36
QuoteBut php does the same "replacestrings", we just do not see itYes,
of course. But as you can see, using map-like view's variables
assignment seems more comfortable than using tag string approach.
Quoteyou do not even need to check for tag string matches. The only
restriction is, that in the template for all fields coming from the
sql query you need use the same tag name as the field name in the
table.Woohoo... I don't think this one is a good idea. Tag string
match is still required in most cases.
Anyway, I guess I'll make the framework myself (but it won't anytime
soon, needs to play on papers first). I've got ideas from our
discussion
----------------------------------------------------------------------
bobo · 2010-10-19 16:52
QuoteWoohoo... I don't think this one is a good idea. Tag string match
is still required in most cases.OK, if ya don't like that, you can do
a
Code: [Select]AView := TStringList.Create;//global webmodule
stringlist property
AView.Add('no=' + SQLQuery.Fields[0].AsString);
AView.Add('name=' + SQLQuery.Fields[1].AsString);
AView.Add('age=' + SQLQuery.Fields[2].AsString);
AResponse.Content := MyTemplate.GetContent;
AView.Free;
//and in the tag handler for MyTemplate you can do a
ReplaceText := AView.Values[TagString];
Better?
----------------------------------------------------------------------
Leledumbo · 2010-10-20 06:02
QuoteBetter?A little. TStringList does support pseudo-map operation,
though it seems a little unnatural. It's not difficult to build a
class like I want (constructed with a template filename and use pure
map operation to assign variables).
What looks difficult is the controller (or in fpWeb jargon, fpWeb
module) inheritance. Consider this example:
The base controller handles request to draw banner and navigation
menu, and provide empty Content variable. The descendant classes fill
that variable with view and data they handle. When a request comes,
it's redirected to the correct descendant classes' method based on
URI, and due to this inheritance the banner and navigation menu still
gets rendered. What's the fpWeb style solution for this?
----------------------------------------------------------------------
bobo · 2010-10-20 17:10
I am not sure you even need to do any fancy object, descendants,
inheritance juggling for this at all.
Webmodules in fpweb handle actions (web requests) and return with
responses to the browser (html pages or page parts in this case).
For this example you can have 3 frames or iframes on your browser
screen.
The top frame/iframe is for the banner, the left frame/iframe is for
the menu, and the remaining one is for the content.
These 3 frames/iframes mean 3 separate requests to the fpweb module
calling different actions in it, lets say ...myserver.com/cgi-
bin/mycgi.cgi/top?param1=1¶m2=2
...myserver.com/cgi-bin/mycgi.cgi/menu?param1=1¶m2=2
...myserver.com/cgi-bin/mycgi.cgi//content?param1=1¶m2=2
They are separate requests to the web module (and therefore to the web
server), and have 3 separate templates for them (which can have
additional embedded parts, etc.). The webmodule action event handler,
can process the session identifying people if needed, can process the
passed URL query parameters or form field values, etc. and using the
proper templates generate the response html parts.
If there is a click on the menu for a new "content" part, then that
URL will only get the response for the new content frame (ex. we can
use the target="framename" for the hyperlinks to get the response into
the proper frame/iframe).
However, I'm not convinced that loading parts of the screens are
really that much of a saving. In my experience generating the screens
as one (even if from multiple templates) works most of the time.
You can do something like a main template and process include
templates instead:
Code: [Select]
{+INCLUDETEMPLATE [-FILE=top.html-]+}
{+INCLUDETEMPLATE [-FILE=body_screen1.html-]+}
{+INCLUDETEMPLATE [-FILE=bottom.html-]+}
And by processing the tag parameter "FILE" you know what template to
use for that part of the response page.
AB
----------------------------------------------------------------------
Leledumbo · 2010-10-21 04:16
QuoteFor this example you can have 3 frames or iframes on your browser
screen.
The top frame/iframe is for the banner, the left frame/iframe is for
the menu, and the remaining one is for the contentI'm avoiding frames
since I prefer strict XHTML doctype instead of frameset.
QuoteThey are separate requests to the web module (and therefore to
the web server)This is what I avoid, except if a webmodule can call
other webmodule's method (thus making the request as light as a method
call).
QuoteHowever, I'm not convinced that loading parts of the screens are
really that much of a saving. In my experience generating the screens
as one (even if from multiple templates) works most of the
time.Exactly.
QuoteYou can do something like a main template and process include
templates instead:Hmm... possible, but I still need to handle those
three parts for EACH request. With inheritance, the top and bottom
could be handled by a base controller and the middle by the correct
descendant.
----------------------------------------------------------------------
bobo · 2010-10-21 07:00
There is no such thing as only parts of the screen handled with using
fpweb exclusively, because nothing runs on the client side in the
browser (at least with the examples we have discussed).
Only when the client keeps parts of the screen (like frames or
iframes, extjs, browser plugins like flash, mono, .net, activex, etc.)
can such thing exist. The client needs to store parts of the web page
screen in these cases.
This puts an overhead and installation requirements on all clients
(all needs the proper version an type plug-in), as well as
compatibility problems across platforms, browser versions, etc.
But if you use a framework like extjs for the gui on the browser side,
this can all be done with fpweb as a back-end. In fact, this way is
the most "RAD" web app development in my opinion for multi-platform.
As for the "inheritance" you are mentioning, it could work with fpweb
too, if you cache the top and left/bottom parts for the user using the
session id into a table or file. If it exists, then you can skip the
generation of that part, if not, then you can generate it once. This
way you do not need to do those parts for every request.
Or you can do some javascript on the client side and replace some
parts of the web page on the client side with the returned html page
parts from the server fpweb app (ex. ajax).
----------------------------------------------------------------------
Leledumbo · 2010-10-21 09:10
QuoteThere is no such thingWhat do you refer this "thing" too?
QuoteBut if you use a framework like extjs for the gui on the browser
side, this can all be done with fpweb as a back-end. In fact, this way
is the most "RAD" web app development in my opinion for multi-
platform.This is of course possible, but the application must be ajax
enabled / web service like instead of standard web application. I
don't consider this as a disadvantage since web service based web
application is very good (example: when other people wants to get the
application data, just parse the xml / json response, no need to
create additional bridge). But most of the time I just want to create
simple web application, without any gui library like extjs or anything
else.
QuoteAs for the "inheritance" you are mentioning, it could work with
fpweb too, if you cache the top and left/bottom parts for the user
using the session id into a table or file. If it exists, then you can
skip the generation of that part, if not, then you can generate it
once. This way you do not need to do those parts for every
request.Possible, maybe just need an additional library to automate
the process. I'll think about it.
----------------------------------------------------------------------
bobo · 2010-10-21 18:16
Well, I am happy that we have arrived from
"...fpWeb have templates, but it's too limited..." and
"...can't handle inheritance or nested templates..."
to an understanding that in fact all can be done relatively easily
with fpweb (FPC 2.5.1 and Lazarus 0.9.29).
Nice.