Recent

Author Topic: Using fpWeb components  (Read 34030 times)

sandeep_c24

  • Full Member
  • ***
  • Posts: 114
Using fpWeb components
« on: February 25, 2009, 10:23:58 am »
Is there any example of how to use components in fpWeb to generate html pages? I want to write web application as apache modules and I am looking at the possibility of using these components.

Sandeep

chrnobel

  • Sr. Member
  • ****
  • Posts: 274
Re: Using fpWeb components
« Reply #1 on: February 25, 2009, 11:35:56 am »
You can use Powtils:

http://z505.com/powtils/idx.shtml

It is quite easy to use, albeit it seems like development has frozen.

/Christian

bobo

  • Full Member
  • ***
  • Posts: 171
Re: Using fpWeb components
« Reply #2 on: February 25, 2009, 07:51:30 pm »
The simplest is to use the TFPTemplate to generate pages. With it you can use template tags in your HTML files that will be replaced in your apache module.
Some info can be found in /packages/fcl-web/fptemplate.txt

sandeep_c24

  • Full Member
  • ***
  • Posts: 114
Re: Using fpWeb components
« Reply #3 on: February 26, 2009, 11:37:51 am »
I had a look at the fptemplate.txt but I could not figure out how to replace!column1value.

Could anyone give a complete example of using templates?

Sandeep

chrnobel

  • Sr. Member
  • ****
  • Posts: 274
Re: Using fpWeb components
« Reply #4 on: February 26, 2009, 02:17:36 pm »
Again, take a closer look at Powtils.

It is very simple to make webapplications, and if you eg. combine it with Zeoslib, you can make very powerful on-line databases.

/Christian

Loesje

  • Full Member
  • ***
  • Posts: 163
    • Lazarus Support website
Re: Using fpWeb components
« Reply #5 on: February 26, 2009, 02:59:56 pm »
Quite a coincidence, I just explained my collegue how to use fpweb.

It totally lacks any documentation, though. And I don't have a simple example. But I can tell you what I told him:

First install fpweb in Lazarus, offcourse. Then create a new cgi-application. You can convert it to an apache-module later.

An empty program with a TFPWebModule will be created. At first, just add a 'OnRequest' event and add the following code:

Code: [Select]
AResponse.contents.add('Hello world');
Handled := True;


Compile the program and place it somewhere where your web-server can find it and recognizes it as a cgi-application (you can use the 'execute after' setting of Lazarus in the compiler options for that goal). Then open it in your web-browser and admire the result... (Hello world)

But that's useless. So now remove the OnRequest event and add an action to the TFPWebModule. Place something like 'Hello world 2' in it's 'content' property and make the action the default. Compile (+copy) and refresh your web-browser.

Now add a second action, give it a name like 'goodbye' and also add 'goodbye' to the content-property. Now you can add '?action=goodbye' to your URL and it will show 'goodbye' instead of 'Hello World 2'.

Now you probably want somewhat more. Drop a THTMLDatasetFormEditProducer on your module and connect it to a datasource linked to a dataset, as you would do normally. You have to set TableCols and TableRows of the producer and add some columns which are bound to some data-fields.

Now set the 'ContentProducer' property of one of the actions to the THTMLDatasetFormEditProducer you just made. Compile and use your webbrowser to open the page with the right action. If all goes well it will show you some data from your dataset...

Last thing for now is how to combine more producers and also add your own tags. That can be done by creating a new action and assign a new THtmlEntityProducer to it. Then create an 'OnWriteEntity' event (Or a 'OnWritePage' event for fpc-versions more then two days old) and add the following code:

Code: [Select]
procedure TwmMain.eHeaderWritePage(Sender: THTMLContentProducer; aWriter: THTMLWriter);
begin
  with aWriter do
    begin
    startHeader;
    Meta('','Content-Type','text/html; charset=ISO-8859-1');
    title('My webpage');
    link('stylesheet','stylesheet.css','text/css','screen');
    EndHeader;
    Startbody;
    paragraph('Some text');
    Image.src := 'logo.png';
    ADatasetFormProducer.WriteContent(aWriter);
    Endbody;
    end;
end;

Just to give you some ideas... Latest fpc-versions also have a THTMLPageProducer component which simply links a header, body and footer together, which I found usefull to use. It's not included by the Lazarus fpweb-packate (yet), though.





bee

  • Sr. Member
  • ****
  • Posts: 393
Re: Using fpWeb components
« Reply #6 on: February 26, 2009, 03:22:25 pm »
fpWeb and Powtils has a different approach which each has it's own advantages and disadvantages. Nobody can't assure you which is the best approach for you but you yourself. It's just a matter of programming habit. If you like the PHP-like (more procedural) way programming habit, then maybe Powtils will suit you more than fpWeb. It'd be another way around if you like VCL-like (very OOP-ish) way programming habit. So, it's just a matter of choice.

Anyway, one thing I'd like to see is FastCGI support from fpWeb package. It should be out of the box as the Apache module support. I prefer to have my web app as an FCGI service rather than as an Apache module. It doesn't force you to restart the whole server if you need to restart your application which somehow I found it's easier to maintain during implementation. ;)

-Bee-

A long time pascal lover.

bobo

  • Full Member
  • ***
  • Posts: 171
Re: Using fpWeb components
« Reply #7 on: February 26, 2009, 10:56:16 pm »
This might be a little long, but I wrote some steps and code snippets about how to use templates (FPTemplate):

Creating CGI or Apache applications with WebModule, using HTML templates (FPTemplate)

Hello World first:

1. File -> New ->  CGI application or Apache module
2. in the Project -> Compiler options put the path to the httpd22 (we are using Apache 2.2 web server) directory into the Other Unit files field
(ex: C:\pp\units\i386-win32\httpd22\)
3. Click inside the webmodule if not already selected
4. In the Object Inspector double click on the "Actions"
5. Click on +Add to create a new action for your web module
6. Change Default to True if you wish this one to be the default action
7. Change the action name to "func1call"  (this will be the calling identifier of this action from the web browser. Something like

http://localhost/mod_apache1/func1call?param1=...)
8. Inside the Events tab, double click on the "OnRequest" to create the procedure called "func1callRequest" that handles this action
9. Enter the following into the procedure body:

procedure TFPWebModule1.func1callRequest(Sender: TObject; ARequest: TRequest;
  AResponse: TResponse; var Handled: Boolean);
begin     
  AResponse.Content := '<html><body>Hello World!</body></html>';

  Handled := true;
end;

10. Save all, compile, configure the apache server to load the module:
in your apache httpd.conf you can put

LoadModule mod_apache1 "/<path to the module>/mod_apache1.dll" #or mod_apache1.so, etc.
<Location /myapache>
    SetHandler mod_apache1
    Order allow,deny
    Allow from all
</Location>

11. Call your module action from your web browser ex: http://localhost/myapache/func1call?param1=paramvalue1
12. See "Hello World!" in your browser
13. Repeat from step 4 for other web actions
==============


Using templates:

1. Lets make a simple html template and save it as mytemplate1.html :

<html>
<body>
This is a replaced template tag: {TagName1}
</body>
</html>

2. Save it and put it somewhere your apache module can access it (ex: below the apache module .dll or .so in a directory called "templates/")
3. Declare a procedure for your web module to handle the template tags

  private
    { private declarations }
    procedure func1callReplaceTag(Sender: TObject; const TagString:String; TagParams: TStringList; Out ReplaceText: String);

4. Create the body of the procedure

procedure TFPWebModule1.func1callReplaceTag(Sender: TObject; const TagString:
  String; TagParams: TStringList; Out ReplaceText: String);
begin
  if AnsiCompareText(TagString, 'TagName1') = 0 then
  begin
    ReplaceText := 'Here I am from the web module!';
  end else begin

//Not found value for tag -> TagString
    ReplaceText := 'Template tag {' + TagString + '} is not implemented yet.';
  end;
end;

5. In step 9 above in the fist example change the procedure body to:

procedure TFPWebModule1.func1callRequest(Sender: TObject; ARequest: TRequest;
  AResponse: TResponse; var Handled: Boolean);
begin     //Template:TFPTemplate is a property of the web Action
  Template.FileName := 'pathtotemplate/mytemplate1.html';
  Template.AllowTagParams := true;
  Template.OnReplaceTag := @func1callReplaceTag;
  AResponse.Content := Template.GetContent;

  Handled := true;
end;

6. Compile, etc. and call it. Should show

This is a replaced template tag: Here I am from the web module!
======================

More complicated HTML template design notes:
1. Template tag delimiters.

  Template.StartDelimiter := '{+';
  Template.EndDelimiter := '+}';
should be used if there are { or } characters in the HTML template (ex: Javascript exist in the template)

more in the FPC /packages/fcl-web/fptemplate.txt

2. For "same as Delphi" template tag handling, use
  Template.StartDelimiter := '<#';
  Template.EndDelimiter := '>';
  Template.ParamStartDelimiter := ' ';
  Template.ParamEndDelimiter := '"';
  Template.ParamValueSeparator := '="';
   
ex: <#TagName1 param1="value1" param2="value2">

more in the FPC /packages/fcl-web/fptemplate.txt
======================

Passing tag parameters:
You can pass parameters to your CGI/Apache web module from the templates.

Example HTML template tag:
{+HereIsATag
 [-param1=param1value-]    //some text here to ignore
-]
 [-param3=param3value-]
+}

ex: {+DATETIME [-FORMAT=MM/DD hh:mm:ss-]+}

Code:
procedure TFPWebModule1.func1callRequest(Sender: TObject; ARequest: TRequest;
  AResponse: TResponse; var Handled: Boolean);
var s:String;
begin     //Template:TFPTemplate is a property of the web Action
  Template.FileName := 'pathtotemplate\templatename.html';
  Template.AllowTagParams := true;
  Template.StartDelimiter := '{+';
  Template.EndDelimiter := '+}';
  Template.OnReplaceTag := @func1callReplaceTag;

  AResponse.Content := Template.GetContent;

  Handled := true;
end;

procedure TFPWebModule1.func1callReplaceTag(Sender: TObject; const TagString:
  String; TagParams: TStringList; Out ReplaceText: String);
begin
  if AnsiCompareText(TagString, 'DATETIME') = 0 then
  begin
    ReplaceText := FormatDateTime(TagParams.Values['FORMAT'], Now);
  end else begin

//Not found value for tag -> TagString
    ReplaceText := 'Template tag {' + TagString + '} is not implemented yet.';
  end;
end;

For example, this way if the web designer changes the look of a page, - in this case the format of the date/time on the page - no changes are needed in the apache module

code, therefore no recompiling or apache restart is needed. The best way is to make the project such, that the web/html design is separated from the back end apache module as much as possible.
« Last Edit: February 26, 2009, 11:00:49 pm by bobo »

bobo

  • Full Member
  • ***
  • Posts: 171
Re: Using fpWeb components
« Reply #8 on: February 26, 2009, 11:42:13 pm »
To answer your question more specifically regarding the fptemplate.txt, here is an example for replacing the html tag using the tag parameters:

procedure TFPWebModule1.func2callReplaceTag(Sender: TObject; const TagString:
  String; TagParams: TStringList; Out ReplaceText: String);
var
   header, footer, onerow, notfound:String;
   NoRecordsToShow, EndOfRecords:Boolean;
begin//HTML template tag handling for one html template file (ex: mytemplate1.html)

  if AnsiCompareText(TagString, 'DATETIME') = 0 then        //Replace the DATETIME html tag from the previous post example
  begin
    ReplaceText := FormatDateTime(TagParams.Values['FORMAT'], Now);
  end else

  if AnsiCompareText(TagString, 'REPORTRESULT') = 0 then    //Replace the REPORTRESULT html tag using it's tag parameters
  begin
    //NoRecordsToShow could be something like SQL1.IsEmpty , etc.
    if NoRecordsToShow then
    begin  //if theres nothing to list, just replace the whole tag with the Not Found message that the template contains
      ReplaceText := TagParams.Values['NOTFOUND'];
      Exit;
    end;

    header := TagParams.Values['HEADER'];
    //insert header parameters
    //1st column title
    header := StringReplace(header, '~Column1', '1st column', []);
    //2nd column title
    header := StringReplace(header, '~Column2', '2nd column', []);

    ReplaceText := header;//done with the header (could have been looping through table field names also)


    //insert the rows
    onerow := TagParams.Values['ONEROW'];//template for 1 row
    //loop through the rows, it could be someting like "while not SQL1.EOF do"
    while not EndOfRecords do
    begin
      ReplaceText := ReplaceText + StringReplace(StringReplace(onerow
                       ,'~Column1Value', '$14.56', [])
                       ,'~Column2Value', '$12.00', []);

      //get the next record, it could be:
      //SQL1.Next
    end;

    //insert the footer
    footer := TagParams.Values['FOOTER'];
    //replace footer parameters if needed
    //...

    ReplaceText := ReplaceText + footer;
  end else begin

//Not found value for tag -> TagString
    ReplaceText := 'Template tag {' + TagString + '} is not implemented yet.';
  end;
end;

sandeep_c24

  • Full Member
  • ***
  • Posts: 114
Re: Using fpWeb components
« Reply #9 on: February 27, 2009, 06:43:13 am »
Thanks everyone for the tips.

Loesje could you please give an example of using THTMLPageProducer?

Sandeep

bobo

  • Full Member
  • ***
  • Posts: 171
Re: Using fpWeb components
« Reply #10 on: February 27, 2009, 07:39:59 pm »
Just in case, I've created some more explanations into fptemplate.txt as well as multiple example projects and step by step instructions how to create these apache/cgi applications.

If you unpack the attached zip file (template-examples.zip) in /packages/fcl-web/ it should all work until
http://bugs.freepascal.org/view.php?id=13250 is applied (a patch to include everything from the zip file into the SVN)


Note if you are making apache modules: "Delete the httpd20 and httpd13 directories (we are making Apache 2.2 modules)
from the fpc directory (ex: C:\pp\units\i386-win32\httpd20\ and
C:\pp\units\i386-win32\httpd13\)
Need to recompile FPC and then Lazarus if FPC was earlier compiled with these
older httpd13 or httpd20 files.
To avoid this recompilation you can also just copy all the files from the
/packages/fcl-web/src/ directory into your project directory so they will
be recompiled as needed."
« Last Edit: February 27, 2009, 07:46:40 pm by bobo »

sandeep_c24

  • Full Member
  • ***
  • Posts: 114
Re: Using fpWeb components
« Reply #11 on: February 27, 2009, 09:55:24 pm »
Thanks bobo. I'll have a look at the examples.

Sandeep

sandeep_c24

  • Full Member
  • ***
  • Posts: 114
Re: Using fpWeb components
« Reply #12 on: February 27, 2009, 11:13:44 pm »
I want to have a Master page(like in asp.net) and then for each action I want to create the body part for that action. This way the look and feel of the website can be handled easily and I would not have to recompile the web-application.

How should I go about doing this? Can this be done easily using THTMLPageProducer or should I stick to using Template for Actions?

Sandeep

sandeep_c24

  • Full Member
  • ***
  • Posts: 114
Re: Using fpWeb components
« Reply #13 on: February 27, 2009, 11:41:29 pm »
How do I generate following using THTMLPageProducer

<form method="post" action="">
  <h2>Login <small>to TrackMe</small></h2>

  <p>
    <label for="txtUser">Username</label>
    <input type="text" name="txtUser" />
  </p>

  <p>
    <label for="txtPwd">Password</label>
    <input type="password" name="txtPwd" />
  </p>

  <p>
    <input type="submit" id="Submit" value="Login" name="btnSubmit">
  </p>
</form>

Sandeep

sandeep_c24

  • Full Member
  • ***
  • Posts: 114
Re: Using fpWeb components
« Reply #14 on: February 28, 2009, 12:31:10 am »
How do I redirect the request to login if the login is not valid?

Sandeep

 

TinyPortal © 2005-2018