Using fpWeb components lazarus / 1-Linux ---------------------------------------------------------------------- sandeep_c24 · 2009-02-25 09:23 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 · 2009-02-25 10:35 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 · 2009-02-25 18:51 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 · 2009-02-26 10:37 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 · 2009-02-26 13:17 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 · 2009-02-26 13:59 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 · 2009-02-26 14:22 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. ---------------------------------------------------------------------- bobo · 2009-02-26 21:56 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 := 'Hello World!';   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 "//mod_apache1.dll" #or mod_apache1.so, etc.     SetHandler mod_apache1     Order allow,deny     Allow from all 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 : This is a replaced template tag: {TagName1} 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. ---------------------------------------------------------------------- bobo · 2009-02-26 22:42 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 · 2009-02-27 05:43 Thanks everyone for the tips. Loesje could you please give an example of using THTMLPageProducer? Sandeep ---------------------------------------------------------------------- bobo · 2009-02-27 18:39 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." ---------------------------------------------------------------------- sandeep_c24 · 2009-02-27 20:55 Thanks bobo. I'll have a look at the examples. Sandeep ---------------------------------------------------------------------- sandeep_c24 · 2009-02-27 22:13 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 · 2009-02-27 22:41 How do I generate following using THTMLPageProducer
 

Login to TrackMe

 

         

 

         

 

     

Sandeep ---------------------------------------------------------------------- sandeep_c24 · 2009-02-27 23:31 How do I redirect the request to login if the login is not valid? Sandeep ---------------------------------------------------------------------- bobo · 2009-02-28 00:26 Maybe return with the html code for the login page again? or if you don't need an error message displayed then AResponse.Content :=   'Redirection' +   '' +   'Please wait...'; or something similar PS: Start new threads for new questions so this thread will not be a project development and hiccup history ---------------------------------------------------------------------- sandeep_c24 · 2009-03-08 10:44 Hi bobo I have now finished my simple website using CGI. It works fine and as expected, but when I converted it to Apache Module it did not work properly. What is happening is I am getting same page for different web actions. When I go to login page I get Login page correctly but when I click some link on the page, which points to another web action I do not see that page but see the Login page. This works properly in CGI. I am using Templates as you explained earlier in this thread. But to me it looks like Template is a property of WebModule rather than of Action and for some reason Templates cannot be changed once assigned. Sandeep ---------------------------------------------------------------------- bobo · 2009-03-08 19:46 Hi, Yes, there are a few patches I have submitted to correct a bunch of problems, but not yet included in the SVN. I have attached a zip file (fcl-web-fixes.zip) that you can unzip in your /packages/fcl-web/ directory to have all the fixes. Just overwrite the files there with the ones in the zip. Also, in the next post I'll attach a bunch of examples on how to use templates (max upload is only 128KB so had to split into two). They needed the above bug fixes to work properly. You can unzip them into the fcl-web directory too. Included fixes: http://bugs.freepascal.org/view.php?id=13228 http://bugs.freepascal.org/view.php?id=13250 http://bugs.freepascal.org/view.php?id=13254 http://bugs.freepascal.org/view.php?id=13280 http://bugs.freepascal.org/view.php?id=13287 http://bugs.freepascal.org/view.php?id=13288 ---------------------------------------------------------------------- bobo · 2009-03-08 19:47 ...here are the examples attached (they require the patches above to work, that are included in the above zip file) ---------------------------------------------------------------------- sandeep_c24 · 2009-03-10 08:41 Hi bobo Thanks for that. The web app is working fine. I'll test it a bit more and get back if I find any problem. Thanks again for the great work. Sandeep ---------------------------------------------------------------------- vfclists · 2010-10-08 19:24 Loesje, do you have a good example of THTMLDatasetFormEditProducer working correctly? I tried it and it was all over the place. The form editor would not update the .lfm correctly, and the placement was hardly logical, and the row and column positioning was simply non existent. There is hardly any proper CSS labelling in the output. Creating objects in code may work, but does laying out rows and columns in the IDE properties really work? I am using a recent svn update, 27548 to be exact. Quote from: Loesje on February 26, 2009, 02:59:56 pmQuite 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:  ----snip-------- 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...  --- snip