From 4a9dd5c8513ed96d1e0cf43e370b170dc38fb502 Mon Sep 17 00:00:00 2001 From: xue <> Date: Fri, 29 Jun 2007 17:41:20 +0000 Subject: finished blog-tutorial. --- .../protected/pages/Day5/ErrorLogging.page | 159 +++++++++++++++++++++ .../protected/pages/Day5/Performance.page | 67 +++++++++ .../protected/pages/Day5/Summary.page | 36 +++++ .../protected/pages/Day5/UseTheme.page | 138 ++++++++++++++++++ .../blog-tutorial/protected/pages/Day5/output.gif | Bin 0 -> 4282 bytes .../blog-tutorial/protected/pages/Day5/output2.gif | Bin 0 -> 7798 bytes .../blog-tutorial/protected/pages/Day5/output3.gif | Bin 0 -> 5190 bytes 7 files changed, 400 insertions(+) create mode 100644 demos/blog-tutorial/protected/pages/Day5/ErrorLogging.page create mode 100644 demos/blog-tutorial/protected/pages/Day5/Performance.page create mode 100644 demos/blog-tutorial/protected/pages/Day5/Summary.page create mode 100644 demos/blog-tutorial/protected/pages/Day5/UseTheme.page create mode 100644 demos/blog-tutorial/protected/pages/Day5/output.gif create mode 100644 demos/blog-tutorial/protected/pages/Day5/output2.gif create mode 100644 demos/blog-tutorial/protected/pages/Day5/output3.gif (limited to 'demos/blog-tutorial/protected/pages/Day5') diff --git a/demos/blog-tutorial/protected/pages/Day5/ErrorLogging.page b/demos/blog-tutorial/protected/pages/Day5/ErrorLogging.page new file mode 100644 index 00000000..52f7ef54 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day5/ErrorLogging.page @@ -0,0 +1,159 @@ + + +

Error Handling and Logging

+ +

+If we try to access the URL http://hostname/blog/index.php?page=EditPost&id=100, we will see the following error page because the post with ID 100 does not exist in our blog system yet. We would like to customize this error page so that it looks more consistent with the other blog pages in layout. We also want to log this kind of errors to study user behaviors. In this section, we will accomplish these two tasks. +

+ + + + +An important task in a Web application is error handling which is often associated logging. There are two types of errors that may occur in a PRADO application: those caused by developers and those by end-users. The former should be resolved before the application is put into production, while the latter are usually within the initial design scope and should be handled nicely (e.g. log the error and display a special page instructing the end-user what to do next.) PRADO implements a very flexible yet powerful framework for error handling and logging. + + + +

Customizing Error Handling

+ +

+PRADO implicitly loads a TErrorHandler module to handle errors. We would like to customize this module so that our blog system can display a customized page for errors caused by end-users. We thus modify the application configuration as follows: +

+ + +...... + + ...... + + ...... + +...... + + +

+The class BlogErrorHandler as specified in the above is a new error handler module that we will create next. It extends and replaces the default TErrorHandler module. +

+ +

+We create a file named protected/BlogErrorHandler.php as follows. The class BlogErrorHandler overrides two methods of TErrorHandler: +

+ + +Prado::using('System.Exceptions.TErrorHandler'); +Prado::using('Application.BlogException'); + +class BlogErrorHandler extends TErrorHandler +{ + /** + * Retrieves the template used for displaying external exceptions. + * This method overrides the parent implementation. + */ + protected function getErrorTemplate($statusCode,$exception) + { + // use our own template for BlogException + if($exception instanceof BlogException) + { + // get the path of the error template file: protected/error.html + $templateFile=Prado::getPathOfNamespace('Application.error','.html'); + return file_get_contents($templateFile); + } + else // otherwise use the template defined by PRADO + return parent::getErrorTemplate($statusCode,$exception); + } + + /** + * Handles external error caused by end-users. + * This method overrides the parent implementation. + * It is invoked by PRADO when an external exception is thrown. + */ + protected function handleExternalError($statusCode,$exception) + { + // log the error (only for BlogException) + if($exception instanceof BlogException) + Prado::log($exception->getErrorMessage(),TLogger::ERROR,'BlogApplication'); + // call parent implementation to display the error + parent::handleExternalError($statusCode,$exception); + } +} + + +

+In the above, we specify that when a BlogException is thrown, we use a new template protected/error.html to display the error. Therefore, we need to create the BlogException class and replace all the occurances of THttpException in our code (such as EditUser and ReadPost pages). We also need to create the error template protected/error.html. The BlogException class extends THttpException and is empty. The class file is saved as protected/BlogException.php. + +

+ + +class BlogException extends THttpException +{ +} + + +

+Below is the content in our error template protected/error.html. Note, the template is not a PRADO template because it only recognizes very limited number of tokens, such as %%ErrorMessage%%, %%ServerAdmin%%. +

+ + + + +%%ErrorMessage%% + + +
+ +
+

%%ErrorMessage%%

+

+The above error happened when the server was processing your request. +

+

+If you think this is a server error, please contact the webmaster. +

+
+ + + + + +

Logging Errors

+ +

+In the handleExternalError() method of BlogErrorHandler, we invoke Prado::log() to log the error if it is of type BlogException. The error is logged in memory. To save the logs into permanent medium such as file or database, we need to enable appropriate error logging routes. This is done in the application configuration as follows: +

+ + +...... + + ...... + + + + ...... + +...... + + +

+In the above, we add a log route that saves logs into a file. We also specify the category filter as BlogApplication such that only the log messages of the selected categories are saved. This helps reduce the size of the log file and also improves its readability. +

+ +

Testing

+

+To see how our blog systems reponds to an invalid user request, we test the URL http://hostname/blog/index.php?page=posts.ReadPost&id=100. We shall see the following error page which is different from what we saw earlier on. +

+ + + +

+If we search under the directory protected/runtime, we will find a file named prado.log. This is the log file that we just configured to save the error messages. The file may contain contents like the following, +

+ + +Jun 28 22:15:27 [Error] [BlogApplication] Unable to find the specified post. +Jun 29 08:42:57 [Error] [BlogApplication] Unable to find the specified post. + + + \ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day5/Performance.page b/demos/blog-tutorial/protected/pages/Day5/Performance.page new file mode 100644 index 00000000..cbaae7e4 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day5/Performance.page @@ -0,0 +1,67 @@ + + +

Performance Tuneup

+ +

+Before we deploy our blog system, we would like to tuneup the system performance. +

+ +

Changing Application Mode

+ +

+A PRADO application may be configured to run in different mode. By default, it runs in debug mode which generates a lot of log messages and in case of errors, it displays full call stack of the error places. Such behavior is preferrable during development, but not so if the system is in production. To change the application mode from Debug to Normal (meaning production mode), we modify the application configuration as follows: +

+ + + + + ...... + + + +

Enabling Caching

+ +

+There are a lot of parsing work involved in a PRADO application: configuration XMLs, templates, theme skins, etc. For every user request, PRADO needs to redo the parsing. To save this effort, we can enable caching. To do so, we modify the application configuration as follows, +

+ + +...... + + ...... + + ...... + +...... + + +

+Now after accessing any page in our blog system, we shall be able to find a file named sqlite3.cache. This is the database file that keeps the parsed page templates, configurations, etc. +

+ + +The cache module we just enabled uses database as persistent cache medium. PRADO also has other cache modules using faster cache medium, such as TMemCache, TAPCCache. They require installation of the corresponding PHP extensions. + + + +

Using pradolite.php

+ +

+Running a PRADO page involves including tens of PHP files, which could be very time-consuming. These files also carry a lot of comments for generating user-friendly API documentation. In order to reduce this cost, we modify index.php and replace the inclusion of prado.php with pradolite.php. The latter is a big file generated by merging necessary PRADO code files and stripping out comments. We thus modify index.php as follows, +

+ +

Other Techniques

+ +

+There are other techniques to further improve the performance of a PRADO application. According to our experience, one of the bottlenecks in a Web application is the database tier. The database queries often take a long time to complete, which greatly degrades the response time of a page request. Caching is the main solution for this problem. The cache module enabled in our application configuration can also be used for this purpose. +

+ +

+For a page that is relatively stable yet frequently accessed, output caching should be considered. Output caching caches the HTML output of selected portions of a page. This may improve the performance of the cached pages significantly. +

+ +

+Server caching techniques are proven to be very effective in improving the performance of PRADO applications. For example, we have observed that by using Zend Optimizer, the RPS (request per second) of a PRADO application can be increased by more than ten times. Of course, this is at the cost of stale output, while PRADO's caching techniques always ensure the correctness of the output. +

+ +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day5/Summary.page b/demos/blog-tutorial/protected/pages/Day5/Summary.page new file mode 100644 index 00000000..3ea350eb --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day5/Summary.page @@ -0,0 +1,36 @@ + + +

Summary

+ +

+We finally can deploy our blog system. To do so, we only need to copy the whole blog directory to the target Web directory. We may need to modify index.php so that it can locate the correct path where the PRADO framework is installed. +

+ +

+So we have completed our blog system. The process may seem not trivial because it takes us nearly five days to reach here. However, as we stated at the beginning, the main purpose of this tutorial is to help PRADO developers get familiar with the commonly used PRADO techniques. The tutorial is not meant to finish a blog system in five minutes and then we learn nothing. +

+ +

+In summary, developing a DB-driven PRADO application involves the following steps: +

+
    +
  1. Design and create database
  2. +
  3. Create initial application layout using prado-cli
  4. +
  5. Set up error handling process to deal with end-user errors
  6. +
  7. Create and set up themes
  8. +
  9. Design and create master classes to share common page layouts
  10. +
  11. Create database classes and set up database connections
  12. +
  13. Design and create various pages
  14. +
  15. Test and tune up performance
  16. +
  17. Deploy the application
  18. +
+ +

+Unlike the order in our tutorial, error handling and creating theme are done earlier in the above process. This is because they often require global change in class code and template. For example, we need to replace THttpException with BlogException in our tutorial. If we define stylesheet classes earlier, we could more easily use them when creating page templates. +

+ +

+As a final tip, try to think in object-oriented way during the design and implementation. Use class inheritance and composition wisely, and you will find the whole project is easier to be developed in parallel by multiple developers. The code also has more chance to be reused so that future projects can be finished much faster. +

+ +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day5/UseTheme.page b/demos/blog-tutorial/protected/pages/Day5/UseTheme.page new file mode 100644 index 00000000..21bc9d81 --- /dev/null +++ b/demos/blog-tutorial/protected/pages/Day5/UseTheme.page @@ -0,0 +1,138 @@ + + +

Using Themes and Skins

+ +

+PRADO has intrinsic support for themes. By using themes, we can better separate logic and presentation, and we can also change the overall appearance of our blog system more easily. +

+ +

Creating Theme

+ +

+We first create a new directory themes. This is the parent directory of all themes for a particular PRADO application. Any subdirectory under this directory will become a theme whose name is the subdirectory name. +

+ +

+To create a theme named Basic, we create a subdirectory theme/Basic. Under this directory, we may place theme-dependent stylesheet files, Javascript files, images, and skin files. +

+ + +The themes directory must be Web-accessible, like the assets directory. Do not place sensitive data files under this directory. You can change the name or location of this directory by configuring the TThemeManager module in the application configuration. + + + +

Creating Stylesheet File

+ +

+Under the themes/Basic directory, we create a CSS stylesheet file named style.css. When a page uses this theme, PRADO will automatically import this stylesheet to the page. The same occurs for Javascript files. +

+ +

+The CSS file is shown as follows. +

+ + +body { + font-family: verdana, 'trebuchet ms', sans-serif; + font-size: 10pt; + background: white; +} +#page { + margin: 0 auto 0 auto; + width: 600px; +} +#footer { + text-align: center; + margin-top: 10px; + padding: 10px; + border-top: 1px solid silver; +} +.post-box { + margin-bottom: 10px; + padding: 5px; +} +.post-box h3 { + padding: 5px; + font-size: 13pt; + background: lightgray; +} +.post-box a { + color: black; + text-decoration: none; +} +.post-box a:hover { + color: red; +} + + + +

Creating Skin File

+ +

+We use skins to initialize the properties of PRADO controls. Skins are stored as skin files (suffix name .skin) under a theme directory. Each skin file can contain multiple skins for one or several types of control. +

+ +

+As a test, we will try to create a skin that changes the background color of the link buttons in the page footer. We create a file named button.skin under the theme directory themes/Basic. +

+ + +<com:THyperLink SkinID="MainMenu" BackColor="lightgreen" /> + + +

+The button.skin skin file contains only one skin for THyperLink controls whose SkinID property is MainMenu. The skin sets the background color of the control to be light-green. +

+ +

+Accordingly, we need to modify protected/common/MainLayout.tpl so that the link buttons in the footer use MainMenu as their SkinID. +

+ +...... + +...... + + + +The syntax for skin files is very similar to that of PRADO templates. Each <com:> tag defines a skin for a particular type of control. PRADO automatically aggregates all skin files in a theme and applies them when a themed page is being rendered. + + + +

Using Theme

+ +

+To use the theme we just created, we modify the application configuration as follows. As we see, the Theme property for all pages is set as Basic, the name of the theme we created. +

+ + +...... + + + + + +...... + + + +It is possible to specify different themes for different pages, and this can be done either in application/page configurations or programmatically (note Theme a page property). For the latter, it is must be done in onPreInit() method of the page because PRADO applies a theme to a page early in the page lifecycle. + + + +

Testing

+

+To see how our blog pages look like, visit the URL http://hostname/blog/index.php. We shall see the font, layout, borders are changed in the page. Also, the link buttons in the footer have light-green background. +

+ + + +
\ No newline at end of file diff --git a/demos/blog-tutorial/protected/pages/Day5/output.gif b/demos/blog-tutorial/protected/pages/Day5/output.gif new file mode 100644 index 00000000..67bd18a3 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day5/output.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day5/output2.gif b/demos/blog-tutorial/protected/pages/Day5/output2.gif new file mode 100644 index 00000000..16c81704 Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day5/output2.gif differ diff --git a/demos/blog-tutorial/protected/pages/Day5/output3.gif b/demos/blog-tutorial/protected/pages/Day5/output3.gif new file mode 100644 index 00000000..6879bbdf Binary files /dev/null and b/demos/blog-tutorial/protected/pages/Day5/output3.gif differ -- cgit v1.2.3