Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7019 Articles
article-image-custom-data-readers-ext-js
Packt
24 Oct 2009
9 min read
Save for later

Custom Data Readers in Ext JS

Packt
24 Oct 2009
9 min read
When writing Chapter 12, "It's All about the Data," of Learning Ext JS, I switched things up a bit and switched the server-side processes to utilizing Adobe's ColdFusion application server, instead of the PHP we had been using in the rest of the book. There were a few reasons we decided to do this. To show that Ext JS can work with any server-side technology. ColdFusion 8 includes Ext JS 1.1 for it's new Ajax form components. Adobe uses a custom format for the serialized JSON return of query data, making it perfect for our example needs. I'm a ColdFusion programmer. Some time ago, before writing Chapter 12, I had begun to use a Custom Data Reader that I had found on the Ext JS forums. Another Ext user and ColdFusion programmer, John Wilson, had written the custom reader to consume Adobe's custom JSON return for queries. First, let me show you why Adobe's format differs from the generally expected serialized JSON return of a query. Here's an example of a typical query response. { 'results': 2, 'rows': [ { 'id': 1, 'firstname': 'Bill', occupation: 'Gardener' }, // a row object { 'id': 2, 'firstname': 'Ben' , occupation: 'Horticulturalist' } // another row object ] } And here's an example of how ColdFusion returns a query response.     {        "COLUMNS":["INTPROPERTIESID","STRDEVELOPMENT","INTADDRESSID", "STRSTREET","STRSTREET2", "STRCITY","CHSTATEID","INTZIP"],        "DATA":[            [2,"Abbey Road",6,"456 Abbey Road","Villa 5","New York","NY",12345],            [6,"Splash",39,"566 aroundthe bend dr",null,"Nashville","TN",37221]        ]    } You can see, when examining the two formats that they are very divergent. The typical format returns an array of row objects of the query's results, whereas ColdFusion's format is an array (DATA) of arrays (each row of the query result), with each row array only containing the data. The ColdFusion format has extracted the column names into it's own array (COLUMNS), as opposed to the name/value pairing found in the object notation of the typical return. It's actually very smart, on Adobe's part, to return the data in this fashion, as it would ultimately mean smaller data sets returned from a remote call, especially with large recordsets. John's CFJsonReader, a custom data reader and an extended component of Ext's base DataReader, was able to translate ColdFusion's data returns by properly parsing the JSON return into Records of an Ext Store. It worked fairly well, with a few minor exceptions. it didn't handle the column aliasing you could do with any other Ext JS data reader (name:'development',mapping:'STRDEVELOPMENT') it didn't allow data type association with a value, as other Ext JS data readers (INTZIP is of type 'int', STRDEVELOPMENT is of type 'string', etc) So, it worked, but ultimately was limited. When I was writing Chapter 13, "Code for Reuse: Extending Ext JS", I really dove into extending existing Ext JS components. This helped me gain a better understanding of what John had done, when writing CFJsonReader. But, after really reviewing the code, I saw there was a better way of handling ColdFusion's JSON return. What it basically came down to was that John was extending Ext's base DataReader object, and then hand parsing almost the entire return. Looking at the above examples, you'll notice that Adobe's implementation is an array of arrays, rather than an array of objects. Ext JS already comes with an ArrayReader object, so I knew that by writing a custom data reader that extended it I would be able to get the desired results. Half an hour later, I had "built a better mousetrap" and we now have a Custom Data Reader for properly parsing ColdFusion's JSON return, without the previous limitations. /* * Ext JS Library 2.0 * Copyright(c) 2006-2007, Ext JS, LLC. * licensing@extjs.com * * http://extjs.com/license * ******************************************* * Steve 'Cutter' Blades (CutterBl) no.junkATcutterscrossingDOTcom * http://blog.cutterscrossing.com * * Inspired by the CFJsonReader, originally writtin by John Wilson (Daemach) * http://extjs.com/forum/showthread.php?t=21408&highlight=cfjsonreader * * This Custom Data Reader will take the JSON return of a ColdFusion * Query object, rather returned straight up, or via the ColdFusion * QueryForGrid() method. * * The CFQueryReader constructor takes two arguments * @meta : object containing single key/value pair for the 'id' of each record * @recordType : field mapping object * * The recordType object allows you to alias the returned ColdFusion column * name (which is always passed in upper case) to any 'name' you wish, as * well as assign a data type, which your ExtJS app will attempt to cast * whenever the value is referenced. * * ColdFusion's JSON return, for a ColdFusion Query object, will appear in the * following format: * * {"COLUMNS":["INTVENDORTYPEID","STRVENDORTYPE","INTEXPENSECATEGORIESID", * "STREXPENSECATEGORIES"],"DATA" :[[2,"Carpet Cleaning",1,"Cleaining"], * [1,"Cleaning Service",1,"Cleaining"]]} * * The ColdFusion JSON return on any query that is first passed through * ColdFusion's QueryForGrid() method will return the object in the * following format: * * {"TOTALROWCOUNT":3, "QUERY":{"COLUMNS":["MYIDFIELD","DATA1","DATA2"], * "DATA":[[1,"Bob","Smith"],[6,"Jim","Brown"]]}} * * The Ext.data.CFQueryReader is designed to accomodate either format * automatically. You would create your reader instance in much the same * way as the CFJsonReader was created: * * var myDataModel = [ * {name: 'myIdField', mapping: 'MYIDFIELD'}, * {name: 'data1', mapping: 'DATA1'}, * {name: 'data2', mapping: 'DATA2'} * ]; * * var myCFReader = new Ext.data.CFJsonReader({id:'myIdField'},myDataModel); * * Notice that the 'id' value mirrors the alias 'name' of the record's field. */ Ext.data.CFQueryReader = function(meta, recordType){ this.meta = meta || {}; Ext.data.CFQueryReader.superclass.constructor.call(this, meta, recordType || meta.fields); }; Ext.extend(Ext.data.CFQueryReader, Ext.data.ArrayReader, { read : function(response){ var json = response.responseText; var o = eval("("+json+")"); if(!o) { throw {message: "JsonReader.read: Json object not found"}; } if(o.TOTALROWCOUNT){ this.totalRowCount = o.TOTALROWCOUNT; } return this.readRecords(((o.QUERY)? o.QUERY : o)); }, readRecords : function(o){ var sid = this.meta ? this.meta.id : null; var recordType = this.recordType, fields = recordType.prototype.fields; var records = []; var root = o.DATA; // give sid an integer value that equates to it's mapping sid = fields.indexOfKey(sid); // re-assign the mappings to line up with the column position // in the returned json response for(var a = 0; a < o.COLUMNS.length; a++){ for(var b = 0; b < fields.length; b++){ if(fields.items[b].mapping == o.COLUMNS[a]){ fields.items[b].mapping = a; } } } for(var i = 0; i < root.length; i++){ var n = root[i]; var values = {}; var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null); for(var j = 0, jlen = fields.length; j < jlen; j++){ var f = fields.items[j]; var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j; var v = n[k] !== undefined ? n[k] : f.defaultValue; v = f.convert(v, n); values[f.name] = v; } var record = new recordType(values, id); record.json = n; records[records.length] = record; } if(!this.totalRowCount){ this.totalRowCount = records.length; } return { records : records, totalRecords : this.totalRowCount }; } }); So, this changes our examples for Chapter 12 just a little bit. First of all, we'll need to have the CFQueryReader included, in place of the CFJsonReader. You can change the script tags in the samples for Examples 3 and 4. ... <script language="javascript" type="text/javascript" src="/scripts/custom-ext/CFQueryReader.js"></script> ... Next, we'll change the scripts for these two examples. We'll remove our configuration references for CFJsonReader, and replace them with the updated configuration for the CFQueryReader. /* * Chapter 12 Example 3 * Data Store from custom reader * * Revised: SGB (Cutter): 12.17.08 * Replaced CFJsonReader with CFQueryReader */ // Save all processing until the // DOM is completely loaded Ext.onReady(function(){ var ourStore = new Ext.data.Store({ url:'Chapter12Example.cfc', baseParams:{ method: 'getFileInfoByPath', returnFormat: 'JSON', queryFormat: 'column', startPath: '/images/' }, reader: new Ext.data.CFQueryReader({ id: 'NAME', // This is supposed to match the 'mapping' fields:[ {name:'file_name',mapping:'NAME'}, {name:'file_size',mapping:'SIZE'}, {name:'type',mapping:'TYPE'}, {name:'lastmod',mapping:'DATELASTMODIFIED'}, {name:'file_attributes',mapping:'ATTRIBUTES'}, {name:'mode',mapping:'MODE'}, {name:'directory',mapping:'DIRECTORY'} ] }), fields: recordModel, listeners:{ beforeload:{ fn: function(store, options){ if (options.startPath && (options.startPath.length > 0)){ store.baseParams.startPath = options.startPath; } }, scope:this }, load: { fn: function(store,records,options){ console.log(records); } }, scope:this } }); ourStore.load(); }); /* * Chapter 12 Example 4 * Data Store from custom reader - Filtering * * Revised: SGB (Cutter): 12.17.08 * Replaced CFJsonReader with CFQueryReader */ // Simple function/object to 'clone' objects cloneConfig = function (config) { for (i in config) { if (typeof config[i] == 'object') { this[i] = new cloneConfig(config[i]); } else this[i] = config[i]; } } // Save all processing until the // DOM is completely loaded Ext.onReady(function(){ var initialBaseParams = { method: 'getDirectoryContents', returnFormat: 'JSON', queryFormat: 'column', startPath: '/testdocs/' }; var ourStore = new Ext.data.Store({ url:'Chapter12Example.cfc', baseParams: new cloneConfig(initialBaseParams), reader: new Ext.data.CFQueryReader({ id: 'NAME', // This is supposed to match the 'mapping' fields:[ {name:'file_name',mapping:'NAME'}, {name:'file_size',mapping:'SIZE'}, {name:'type',mapping:'TYPE'}, {name:'lastmod',mapping:'DATELASTMODIFIED'}, {name:'file_attributes',mapping:'ATTRIBUTES'}, {name:'mode',mapping:'MODE'}, {name:'directory',mapping:'DIRECTORY'} ] }), listeners:{ beforeload:{ fn: function(store, options){ for(var i in options){ if(options[i].length > 0){ store.baseParams[i] = options[i]; } } }, scope:this }, load: { fn: function(store, records, options){ console.log(records); }, scope: this }, update: { fn: function(store, record, operation){ switch (operation){ case Ext.record.EDIT: // Do something with the edited record break; case Ext.record.REJECT: // Do something with the rejected record break; case Ext.record.COMMIT: // Do something with the committed record break; } }, scope:this } } }); ourStore.load({recurse:true}); filterStoreByType = function (type){ ourStore.load({dirFilter:type}); } filterStoreByFileType = function (fileType){ ourStore.load({fileFilter:fileType}); } clearFilters = function (){ ourStore.baseParams = new cloneConfig(initialBaseParams); ourStore.load(); } }); Summary These very basic changes have no overall effect on our examples. They function exactly as they did before. The new Custom Data Reader loads the data, returned from ColdFusion, exactly as it should. Now, we can also work with these data stores in the same manor as we would with any other data store set up through Ext JS, having the ability to alias columns, define field data types, and more.
Read more
  • 0
  • 0
  • 5023

article-image-rss-web-widget
Packt
24 Oct 2009
8 min read
Save for later

RSS Web Widget

Packt
24 Oct 2009
8 min read
What is an RSS Feed? First of all, let us understand what a web feed is. Basically, it is a data format that provides frequently updated content to users. Content distributors syndicate the web feed, allowing users to subscribe, by using feed aggregator. RSS feeds contain data in an XML format. RSS is the term used for describing Really Simple Syndication, RDF Site Summary, or Rich Site Summary, depending upon the different versions. RDF (Resource Description Framework), a family of W3C specification, is a data model format for modelling various information such as title, author, modified date, content etc through variety of syntax format. RDF is basically designed to be read by computers for exchanging information. Since, RSS is an XML format for data representation, different authorities defined different formats of RSS across different versions like 0.90, 0.91, 0.92, 0.93, 0.94, 1.0 and 2.0. The following table shows when and by whom were the different RSS versions proposed. RSS Version Year Developer's Name RSS 0.90 1999 Netscape introduced RSS 0.90. RSS 0.91 1999 Netscape proposed the simpler format of RSS 0.91. 1999 UserLand Software proposed the RSS specification. RSS 1.0 2000 O'Reilly released RSS 1.0. RSS 2.0 2000 UserLand Software proposed the further RSS specification in this version and it is the most popular RSS format being used these days. Meanwhile, Harvard Law school is responsible for the further development of the RSS specification. There had been a competition like scenario for developing the different versions of RSS between UserLand, Netscape and O'Reilly before the official RSS 2.0 specification was released. For a detailed history of these different versions of RSS you can check http://www.rss-specifications.com/history-rss.htm The current version RSS is 2.0 and it is the common format for publishing RSS feeds these days. Like RSS, there is another format that uses the XML language for publishing web feeds. It is known as ATOM feed, and is most commonly used in Wiki and blogging software. Please refer to http://en.wikipedia.org/wiki/ATOM for detail. The following is the RSS icon that denotes links with RSS feeds. If you're using Mozilla's Firefox web browser then you're likely to see the above image in the address bar of the browser for subscribing to an RSS feed link available in any given page. Web browsers like Firefox and Safari discover available RSS feeds in web pages by looking at the Internet media type application/rss+xml. The following tag specifies that this web page is linked with the RSS feed URL: http://www.example.com/rss.xml<link href="http://www.example.com/rss.xml" rel="alternate" type="application/rss+xml" title="Sitewide RSS Feed" /> Example of RSS 2.0 format First of all, let’s look at a simple example of the RSS format. <?xml version="1.0" encoding="UTF-8" ?><rss version="2.0"><channel> <title>Title of the feed</title> <link>http://www.examples.com</link> <description>Description of feed</description> <item> <title>News1 heading</title> <link>http://www.example.com/news-1</link> <description>detail of news1 </description> </item> <item> <title>News2 heading</title> <link>http://www.example.com/news-2</link> <description>detail of news2 </description> </item></channel></rss> The first line is the XML declaration that indicates its version is 1.0. The character encoding is UTF-8. UTF-8 characters support many European and Asian characters so it is widely used as character encoding in web. The next line is the rss declaration, which declares that it is a RSS document of version 2.0 The next line contains the <channel> element which is used for describing the detail of the RSS feed. The <channel> element must have three required elements <title>, <link> and <description>. The title tag contains the title of that particular feed. Similarly, the link element contains the hyperlink of the channel and the description tag describes or carries the main information of the channel. This tag usually contains the information in detail. Furthermore, each <channel> element may have one or more <item> elements which contain the story of the feed. Each <item> element must have the three elements <title>, <link> and <description> whose use is similar to those of channel elements, but they describe the details of each individual items. Finally, the last two lines are the closing tags for the <channel> and <rss> elements. Creating RSS Web Widget The RSS widget we're going to build is a simple one which displays the headlines from the RSS feed, along with the title of the RSS feed. This is another widget which uses some JavaScript, PHP CSS and HTML. The content of the widget is displayed within an Iframe so when you set up the widget, you've to adjust the height and width. To parse the RSS feed in XML format, I've used the popular PHP RSS Parser – Magpie RSS. The homepage of Magpie RSS is located at http://magpierss.sourceforge.net/. Introduction to Magpie RSS Before writing the code, let's understand what the benefits of using the Magpie framework are, and how it works. It is easy to use. While other RSS parsers are normally limited for parsing certain RSS versions, this parser parses most RSS formats i.e. RSS 0.90 to 2.0, as well as ATOM feed. Magpie RSS supports Integrated Object Cache which means that the second request to parse the same RSS feed is fast— it will be fetched from the cache. Now, let's quickly understand how Magpie RSS is used to parse the RSS feed. I'm going to pick the example from their homepage for demonstration. require_once 'rss_fetch.inc';$url = 'http://www.getacoder.com/rss.xml';$rss = fetch_rss($url);echo "Site: ", $rss->channel['title'], "<br>";foreach ($rss->items as $item ) { $title = $item[title]; $url = $item[link]; echo "<a href=$url>$title</a></li><br>";} If you're more interested in trying other PHP RSS parsers then you might like to check out SimplePie RSS Parser (http://simplepie.org/) and LastRSS (http://lastrss.oslab.net/). You can see in the first line how the rss_fetch.inc file is included in the working file. After that, the URL of the RSS feed from getacoder.com is assigned to the $url variable. The fetch_rss() function of Magpie is used for fetching data and converting this data into RSS Objects. In the next line, the title of RSS feed is displayed using the code $rss->channel['title']. The other lines are used for displaying each of the RSS feed's items. Each feed item is stored within an $rss->items array, and the foreach() loop is used to loop through each element of the array. Writing Code for our RSS Widget As I've already discussed, this widget is going to use Iframe for displaying the content of the widget, so let's look at the JavaScript code for embedding Iframe within the HTML code. var widget_string = '<iframe src="http://www.yourserver.com/rsswidget/rss_parse_handler.php?rss_url=';widget_string += encodeURIComponent(rss_widget_url);widget_string += '&maxlinks='+rss_widget_max_links;widget_string += '" height="'+rss_widget_height+'" width="'+rss_widget_width+'"';widget_string += ' style="border:1px solid #FF0000;"';widget_string +=' scrolling="no" frameborder="0"></iframe>';document.write(widget_string); In the above code, the widget string variable contains the string for displaying the widget. The source of Iframe is assigned to rss_parse_handler.php. The URL of the RSS feed, and the headlines from the feed are passed to rss_parse_handler.php via the GET method, using rss_url and maxlinks parameters respectively. The values to these parameters are assigned from the Javascript variables rss_widget_url and rss_widget_max_links. The width and height of the Iframe are also assigned from JavaScript variables, namely rss_widget_width and rss_widget_height. The red border on the widget is displayed by assigning 1px solid #FF0000 to the border attribute using the inline styling of CSS. Since, Inline CSS is used, the frameborder property is set to 0 (i.e. the border of the frame is zero). Displaying borders from the CSS has some benefit over employing the frameborder property. While using CSS code, 1px dashed #FF0000 (border-width border-style border-color) means you can display a dashed border (you can't using frameborder), and you can use the border-right, border-left, border-top, border-bottom attributes of CSS to display borders at specified positions of the object. The scrolling property is set to no here, which means that the scroll bar will not be displayed in the widget if the widget content overflows. If you want to show a scroll bar, then you can set this property to yes. The values of JavaScript variables like rss_widget_url, rss_widget_max_links etc come from the page where we'll be using this widget. You'll see how the values of these variables will be assigned from the section at the end where we'll look at how to use this RSS widget.  
Read more
  • 0
  • 0
  • 4517

article-image-copying-database-sql-server-2005-sql-server-2008-using-copy-database-wizard
Packt
24 Oct 2009
3 min read
Save for later

Copying a Database from SQL Server 2005 to SQL Server 2008 using the Copy Database Wizard

Packt
24 Oct 2009
3 min read
(For more resources on Microsoft, see here.) Using the Copy Database Wizard you will be creating an SQL Server Integration Services package which will be executed by an SQL Server Agent job. It is therefore necessary to set up the SQL Server Agent to work with a proxy that you need to create which can execute the package. Since the proxy needs a credential to workout outside the SQL 2008 boundary you need to create a Credential and a Principal who has the permissions. Creating a credential has been described elsewhere. The main steps in migration using this route are: Create an Credential Create an SQL Server Agent Proxy to work with SSIS Package execution Create the job using the Copy Database Wizard Creating the Proxy In the SQL Server 2008 Management Studio expand the SQL Server Agent node and then expand the Proxies node. You can create proxies for various actions that you may undertake. In the present case the Copy Database wizard creates an Integration Services package and therefore a proxy is needed for this. Right click the SSIS Package Execution folder as shown in the next figure. Click on New Proxy.... This opens the New Proxy Account window as shown. Here Proxy name is the one you provide which will be needed in the Copy Database Wizard. Credential name is the one you created earlier which uses a database login name and password. Description is an optional info to keep track of the proxy. As seen in the previous figure you can create different proxies to deal with different activities. In the present case a proxy will be created for Integration Service Package execution as shown in the next figure. The name CopyPubx has been created as shown. Now click on the ellipsis button along the Credential name and this brings up the Select Credential window as shown. Now click on the Browse... button. This brings up the Browse for Objects window displaying the credential you created earlier. Place a checkmark as shown and click on the OK button. The [mysorian] credential is entered into the Select Credential window. Click on the OK button on the Select Credential window. The credential name gets entered into the New Proxy Account's Credential name. The optional description can be anything suitable as shown. Place a checkmark on the SQL Server Integration Services Package as shown and click on Principals. Since the present proxy is going to be used by the sysadmin, there is no need to add it specifically. Click on the OK button to close this New Proxy Account window. You can now expand the SSIS Package Execution node of the Proxies and verify that CopyPubx has been added. There are two other proxies created in the same way in this folder. Since the SQL Server Agent is needed for this process to succeed, make sure the SQL Server Agent is running. If it has not started yet, you can start this service from the Control Panel.  
Read more
  • 0
  • 0
  • 9030

article-image-dynamic-theming-drupal-6-part-2
Packt
24 Oct 2009
8 min read
Save for later

Dynamic Theming in Drupal 6 - Part 2

Packt
24 Oct 2009
8 min read
Creating Dynamic CSS Styling In addition to creating dynamic templates, the Drupal system also enables you to apply CSS dynamically. Drupal creates unique identifiers for various elements of the system and you can use those identifiers to create specific CSS selectors. As a result, you can provide styling that responds to the presence (or absence) of specific conditions on any given page. Two of the most common uses of this technique are covered below: The creation of node-specific styles and the use of $body_classes. Using Dynamic Selectors for Nodes The system generates a unique ID for each node on the website. We can use that unique ID to activate a unique selector by applying this nomenclature for the selector: #node-[nid] {} For example, assume you wish to add a border to the node with the ID of 2. Simply create a new div in style.css with the name: #node-2 {border: 1px solid #336600} Changing the Body Class Based on body_classes One of the most useful dynamic styling tools introduced in Drupal 6 is the implementation of $body_classes. This variable is intended specifically as an aid to dynamic CSS styling. It allows for the easy creation of CSS selectors that are responsive to the layout of the page. This technique is typically used to control the styling where there may be one, two or three columns displayed, depending on the page and the content. Prior to Drupal 6, $layout was used to detect the page layout, that is, one, two or three columns. While $layout can technically still be used, the better practice is to use $body_classes. Implementing $body_classes is a simple matter; just add $body_classes to the body tag of your page.tpl.php file—the Drupal system will do the rest. Once the body tag is altered to include this variable, the class associated with the body tag will change automatically in response to the conditions on the page at that time. Now, all you have to do is create the CSS selectors that you wish to see applied in the various situations. Let's step through this with a quick example. Open up your page.tpl.php file and modify the body tag as follows: <body class="<?php print $body_classes; ?>"> This will now automatically create a class for the page based on the conditions on the page. The chart below shows the options this presents: Condition Class Available no sidebars .no-sidebar one sidebar .one-sidebar left sidebar visible .sidebar-left right sidebar visible .sidebar-right two sidebars .two-sidebars front page .front not front page .not-front logged in .logged-in not logged in .not-logged-in page visible .page-[page type               node visible .node-type-[name of type]       $body_classes provides the key to easily creating a theme that includes collapsible sidebars. To set up this functionality, modify the page.tpl.php file to include $body_classes. Now, go to the style.css file and create the following selectors: .one-sidebar {}.sidebar-left {}.sidebar-right {}.no-sidebar {}.two-sidebars {} The final step is to create the styling for each of the selectors above (as you see fit). When the site is viewed, the system-generated value of $body_classes will determine which selector is applied. You can now specify, through the selectors above, exactly how the page appears—whether the columns collapse, the resulting widths of the remaining columns, and so on , and so on. Working with Template Variables As we have seen, above, Drupal produces variables that can be used to enhance the functionality of themes. Typically, a theme-related function returns values reflecting the state of the page on the screen. A function may indicate, for example, whether the page is the front page of the site, or whether there are one, two, or three active columns (for example, the variable $body_classes). Tapping into this information is a convenient way for a theme developer to style a site dynamically. The default Drupal variables cover the most common (and essential) functions, including creating unique identifiers for items. Some of the Drupal variables are unique to particular templates; others are common to all. In addition to the default variables, you can also define your own variables. Using the function theme_preprocess(), you can either set new variables, or unset existing ones that you do not want to use. In Drupal 6, preprocess functions have made working with variables easier and cleaner. By using the preprocessor, you can set up variables within your theme that can be accessed by any of your templates. The code for the preprocess function is added to your template.php file, thereby keeping the actual template files (the .tpl.php files) free of unnecessary clutter. Note that the preprocess functions only apply to theming hooks implemented as templates; plain theme functions do not interact with the preprocessors. In Drupal 5 and below, the function _phptemplate_variables served the same purpose as the preprocess function. For a list of the expected preprocess functions and their order of precedence, see http://drupal.org/node/223430 Typically, if you wish to implement a preprocessor applicable to your theme, you will use one of the following:   Name of preprocessor Application [engineName]_preprocess This namespace should be used for your base theme. Should be named after the theme engine used by the theme. Will apply to all hooks. [engineName]_preprocess_ [hookname] Should be used for your base theme. Also named after the theme engine applicable to the theme but note that it is specific to a single hook. [themeName]_preprocess This namespace should be used for subthemes. Will apply to all hooks. [themeName]_preprocess_ [hookname] Should be used for subthemes. Note that it is specific to a single hook. Let's look first at intercepting and overriding the default variables and then at creating your own variables. Intercepting and Overriding Variables You can intercept and override the system's existing variables. Intercepting a variable is no different in practice from intercepting a themable function: you simply restate it in the template.php file and make your modifications there, leaving the original code in the core intact. To intercept an existing variable and override it with your new variable, you need to use the function _phptemplate_preprocess(). Add this to your template.php file according to the following syntax: <?phpfunction phptemplate_preprocess(&$vars) {$vars['name'] = add your code here...;}?> Note that nothing should be returned from these functions. The variables have to be passed by reference, as indicated by the ampersand before variables, e.g., &$vars. Let's take a very basic example and apply this. Let's override $title inpage.tpl.php. To accomplish this task, add the following code to the template.php file: <?php function phptemplate_preprocess(&$vars) { $vars['title'] = 'override title';}?> Remember to clear your theme registry! With this change made and the file saved to your theme, the string override title will appear, substituted for the original $title value. Making New Variables Available The preprocess function also allows you to define additional variables in your theme. To create a new variable, you must declare the function in the template.php file. In order for your theme to have its preprocessors recognized, the template associated with the hook must exist inside the theme. If the template does not exist in your theme, copy one and place it in the theme directory. The syntax is the same as that just used for intercepting and overriding a variable, as seen above. The ability to add new variables to the system is a powerful tool and gives you the ability to add more complex logic to your theme. Summary In this two part article we covered the basics needed to make your Drupal theme responsive to the contents and the users. By applying the techniques discussed here, you can control the theming of pages based on content, state of the page or the users viewing them. Taking the principles one step further, you can also make the theming of elements within a page conditional. The ability to control the templates used and the styling of the page and its elements is what we call dynamic theming. We covered not only the basic ideas behind dynamic theming, but also the techniques needed to implement this powerful tool. Among the items discussed at length were the use of suggestions to control template display, and the implementation of $body_classes. Also covered in this article, was the use of the preprocess function to work with variables inside your theme
Read more
  • 0
  • 0
  • 1770

article-image-cooking-xml-oop
Packt
23 Oct 2009
9 min read
Save for later

Cooking XML with OOP

Packt
23 Oct 2009
9 min read
Formation of XML Let us look at the structure of a common XML document in case you are totally new to XML. If you are already familiar with XML, which we greatly recommend for this article, then it is not a section for you. Let's look at the following example, which represents a set of emails: <?xml version="1.0" encoding="ISO-8859-1" ?><emails> <email> <from>nowhere@notadomain.tld</from> <to>unknown@unknown.tld</to> <subject>there is no subject</subject> <body>is it a body? oh ya</body> </email></emails> So you see that XML documents do have a small declaration at the top which details the character set of the document. This is useful if you are storing Unicode texts. In XML, you must close the tags as you start it. (XML is more strict than HTML, you must follow the conventions.) Let's look at another example where there are some special symbols in the data: <?xml version="1.0" encoding="ISO-8859-1" ?><emails> <email> <from>nowhere@notadomain.tld</from> <to>unknown@unknown.tld</to> <subject>there is no subject</subject> <body><![CDATA[is it a body? oh ya, with some texts & symbols]]></body> </email></emails> This means you have to enclose all the strings containing special characters with CDATA. Again, each entity may have some attributes with it. For example consider the following XML where we describe the properties of a student: <student age= "17" class= "11" title= "Mr.">Ozniak</student> In the above example, there are three attributes to this student tag—age, class, and title. Using PHP we can easily manipulate them too. In the coming sections we will learn how to parse XML documents, or how to create XML documents on the fly. Introduction to SimpleXML In PHP4 there were two ways to parse XML documents, and these are also available in PHP5. One is parsing documents via SAX (which is a standard) and another one is DOM. But it takes quite a long time to parse XML documents using SAX and it also needs quite a long time for you to write the code. In PHP5 a new API has been introduced to easily parse XML documents. This was named SimpleXML API. Using SimpleXML API you can turn your XML documents into an array. Each node will be converted to an accessible form for easy parsing. Parsing Documents In this section we will learn how to parse basic XML documents using SimpleXML. Let's take a breath and start. $str = <<< END<emails> <email> <from>nowhere@notadomain.tld</from> <to>unknown@unknown.tld</to> <subject>there is no subject</subject> <body><![CDATA[is it a body? oh ya, with some texts & symbols]]></body> </email></emails>END;$sxml = simplexml_load_string($str);print_r($sxml);?> The output is like this: SimpleXMLElement Object( [email] => SimpleXMLElement Object ( [from] => nowhere@notadomain.tld [to] => unknown@unknown.tld [subject] => there is no subject [body] => SimpleXMLElement Object ( ) )) So now you can ask how to access each of these properties individually. You can access each of them like an object. For example, $sxml->email[0] returns the first email object. To access the from element under this email, you can use the following code like: echo $sxml->email[0]->from So, each object, unless available more than once, can be accessed just by its name. Otherwise you have to access them like a collection. For example, if you have multiple elements, you can access each of them using a foreach loop: foreach ($sxml->email as $email)echo $email->from; Accessing Attributes As we saw in the previous example, XML nodes may have attributes. Remember the example document with class, age, and title? Now you can easily access these attributes using SimpleXML API. Let's see the following example: <?$str = <<< END<emails> <email type="mime"> <from>nowhere@notadomain.tld</from> <to>unknown@unknown.tld</to> <subject>there is no subject</subject> <body><![CDATA[is it a body? oh ya, with some texts & symbols]]></body> </email></emails>END;$sxml = simplexml_load_string($str);foreach ($sxml->email as $email)echo $email['type'];?> This will display the text mime in the output window. So if you look carefully, you will understand that each node is accessible like properties of an object, and all attributes are accessed like keys of an array. SimpleXML makes XML parsing really fun. Parsing Flickr Feeds using SimpleXML How about adding some milk and sugar to your coffee? So far we have learned what SimpleXML API is and how to make use of it. It would be much better if we could see a practical example. In this example we will parse the Flickr feeds and display the pictures. Sounds cool? Let's do it. If you are interested what the Flickr public photo feed looks like, here is the content. The feed data is collected from http://www.flickr.com/services/feeds/photos_public.gne: <?xml version="1.0" encoding="utf-8" standalone="yes"?><feed > <title>Everyone's photos</title> <link rel="self" href="http://www.flickr.com/services/feeds/photos_public.gne" /> <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/"/> <id>tag:flickr.com,2005:/photos/public</id> <icon>http://www.flickr.com/images/buddyicon.jpg</icon> <subtitle></subtitle> <updated>2007-07-18T12:44:52Z</updated> <generator uri="http://www.flickr.com/">Flickr</generator> <entry> <title>A-lounge 9.07_6</title> <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/dimitranova/845455130/"/> <id>tag:flickr.com,2005:/photo/845455130</id> <published>2007-07-18T12:44:52Z</published> <updated>2007-07-18T12:44:52Z</updated> <dc:date.Taken>2007-07-09T14:22:55-08:00</dc:date.Taken> <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/people/dimitranova/&quot; &gt;Dimitranova&lt;/a&gt; posted a photo:&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/dimitranova/845455130/ &quot; title=&quot;A-lounge 9.07_6&quot;&gt;&lt;img src=&quot; http://farm2.static.flickr.com/1285/845455130_dce61d101f_m.jpg &quot; width=&quot;180&quot; height=&quot;240&quot; alt=&quot; A-lounge 9.07_6&quot; /&gt;&lt;/a&gt;&lt;/p&gt;</content> <author> <name>Dimitranova</name> <uri>http://www.flickr.com/people/dimitranova/</uri> </author> <link rel="license" type="text/html" href="deed.en-us" /> <link rel="enclosure" type="image/jpeg" href="http://farm2.static.flickr.com/1285/ 845455130_7ef3a3415d_o.jpg" /> </entry> <entry> <title>DSC00375</title> <link rel="alternate" type="text/html" href="http://www.flickr.com/photos/53395103@N00/845454986/"/> <id>tag:flickr.com,2005:/photo/845454986</id> <published>2007-07-18T12:44:50Z</published>...</entry></feed> Now we will extract the description from each entry and display it. Let's have some fun: <?$content = file_get_contents( "http://www.flickr.com/services/feeds/photos_public.gne ");$sx = simplexml_load_string($content);foreach ($sx->entry as $entry){ echo "<a href='{$entry->link['href']}'>".$entry->title."</a><br/>"; echo $entry->content."<br/>"; }?> This will create the following output. See, how easy SimpleXML is? The output of the above script is shown below: Managing CDATA Sections using SimpleXML As we said before, some symbols can't appear directly as a value of any node unless you enclose them using CDATA tag. For example, take a look at following example: <?$str = <<<EOT<data> <content>text & images </content></data>EOT;$s = simplexml_load_string($str);?> This will generate the following error: <br /><b>Warning</b>: simplexml_load_string() [<a href='function.simplexml-load-string'> function.simplexml-load-string</a>]: Entity: line 2: parser error : xmlParseEntityRef: no name in <b>C:OOP with PHP5Codesch8cdata.php</b> on line <b>10</b><br /><br /><b>Warning</b>: simplexml_load_string() [<a href='function.simplexml-load-string'> function.simplexml-load-string</a>]: &lt;content&gt;text &amp; images &lt;/content&gt; in <b>C:OOP with PHP5Codesch8cdata.php</b> on line <b>10</b><br /><br /><b>Warning</b>: simplexml_load_string() [<a href='function.simplexml-load-string'> function.simplexml-load-string</a>]: ^ in <b>C:OOP with PHP5Codesch8cdata.php</b> on line <b>10</b><br /> To avoid this problem we have to enclose using a CDATA tag. Let's rewrite it like this: <data> <content><![CDATA[text & images ]]></content></data> Now it will work perfectly. And you don't have to do any extra work for managing this CDATA section. <?$str = <<<EOT<data> <content><![CDATA[text & images ]]></content></data>EOT;$s = simplexml_load_string($str);echo $s->content;//print "text & images"?> However, prior to PHP5.1, you had to load this section as shown below: $s = simplexml_load_string($str,null,LIBXML_NOCDATA);
Read more
  • 0
  • 0
  • 2504

article-image-joomla-and-database
Packt
23 Oct 2009
8 min read
Save for later

Joomla! and Database

Packt
23 Oct 2009
8 min read
The Core Database Much of the data we see in Joomla! is stored in the database. A base installation has over thirty tables. Some of these are related to core extensions and others to the inner workings of Joomla!. There is an official database schema, which describes the tables created during the installation. For more information, please refer to: http://dev.joomla.org/ component/option,com_jd-wiki/Itemid,31/id,guidelines:database/. A tabular description is available at: http://dev.joomla.org/downloads/Joomla15_DB-Schema.htm. We access the Joomla! database using the global JDatabase object. The JDatabase class is an abstract class, which is extended by different database drivers. There are currently only two database drivers included in the Joomla! core, MySQL and MySQLi. We access the global JDatabase object using JFactory: $db =& JFactory::getDBO(); Extending the Database When we create extensions, we generally want to store data in some form. If we are using the database, it is important to extend it in the correct way. Table Prefix All database tables have a prefix, normally jos_, which helps in using a single database for multiple Joomla! installations. When we write SQL queries, to accommodate the variable table prefix, we use a symbolic prefix that is substituted with the actual prefix at run time. Normally the symbolic prefix is #__, but we can specify an alternative prefix if we want to. Schema Conventions When we create tables for our extensions, we must follow some standard conventions. The most important of these is the name of the table. All tables must use the table prefix and should start with name of the extension. If the table is storing a specific entity, add the plural of the entity name to the end of the table name separated by an underscore. For example, an items table for the extension 'My Extension' would be called #__myExtension_items. Table field names should all be lowercase and use underscore word separators; you should avoid using underscores if they are not necessary. For example, you can name an email address field as email. If you had a primary and a secondary email field, you could call them email and email_secondary; there is no reason to name the primary email address email_primary. If you are using a primary key record ID, you should call the field id, make it of type integer auto_increment, and disallow null. Doing this will allow you to use the Joomla! framework more effectively. Common Fields We may use some common fields in our tables. Using these fields will enable us to take advantage of the Joomla! framework. Publishing We use publishing to determine whether to display data. Joomla! uses a special field called published, of type tinyint(1); 0 = not published, 1 = published. Hits If we want to keep track of the number of times a record has been viewed, we canuse the special field hits, of type integer and with the default value 0. Checking Out To prevent more than one user trying to edit one record at a time we can check out records (a form of software record locking). We use two fields to do this, checked_out and checked_out_time. checked_out, of type integer, holds the ID of the user that has checked out the record. checked_out_time, of type datetime, holds the date and time when the record was checked out. A null date and a user ID of 0 is recorded if the record is not checked out. Ordering We often want to allow administrators the ability to choose the order in which items appear. The ordering field, of type integer, can be used to number records sequentially to determine the order in which they are displayed. This field does not need to be unique and can be used in conjunction with WHERE clauses to form ordering groups. Parameter Fields We use a parameter field, a TEXT field normally named params, to store additional information about records; this is often used to store data that determines how a record will be displayed. The data held in these fields is encoded as INI strings (which we handle using the JParameter class). Before using a parameter field, we should carefully consider the data we intend to store in the field. Data should only be stored in a parameter field if all of the following criteria are true: Not used for sorting records Not used in searches Only exists for some records Not part of a database relationship Schema Example Imagine we have an extension called 'My Extension' and an entity called foobar. The name of the table is #__myextension_foobars. This schema describes the table: Field Datatype NOT NULL AUTO INC UNSIGNED DEFAULT id INTEGER X X X NULL content TEXT X       checked_out INTEGER X   X 0 checked_out_time DATETIME X     0000-00-00 00:00:00 params TEXT X       ordering INTEGER X   X 0 hits INTEGER X   X 0 published TINYINT(1) X   X 0 This table uses all of the common fields and uses an auto-incrementing primary keyID field. When we come to define our own tables we must ensure that we use thecorrect data types and NOT NULL, AUTO INC, UNSIGNED and DEFAULT values. The SQL displayed below will create the table described in the above schema: CREATE TABLE `#__myextension_foobars` ( `id` INTEGER UNSIGNED NOT NULL DEFAULT NULL AUTO_INCREMENT, `content` TEXT NOT NULL DEFAULT '', `checked_out` INTEGER UNSIGNED NOT NULL DEFAULT 0, `checked_out_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', `params` TEXT NOT NULL DEFAULT '', `ordering` INTEGER UNSIGNED NOT NULL DEFAULT 0, `hits` INTEGER UNSIGNED NOT NULL DEFAULT 0, `published` INTEGER UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY(`id`)) CHARACTER SET `utf8` COLLATE `utf8_general_ci`; Date Fields We regularly use datetime fields to record the date and time at which an action has taken place. When we use these fields, it is important that we are aware of the effect of time zones. All dates and times should be recorded in UTC+0 (GMT / Z). When we come to display dates and times we can use the JDate class. The JDate class allows us to easily parse dates, output them in different formats, and apply UTC time-zone offsets. For more information about time zones, please refer to http://www.timeanddate.com. We often use parsers before we display data to make the data safe or to apply formatting to the data. We need to be careful how we store data that is going to be parsed. If the data is ever going to be edited, we must store the data in its RAW state. If the data is going to be edited extremely rarely and if the parsing is reversible, we may want to consider building a 'reverse-parser'. This way we can store the data in its parsed format, eradicating the need for parsing when we view the data and reducing the load on the server. Another option available tous is to store the data in both formats. This way we only have to parse data when we save it. Dealing with Multilingual Requirements Unlike ASCII and ANSII, Unicode is a multi-byte character set; it uses more than eight bits (one byte) per character. When we use UTF-8 encoding, character byte lengths vary. Unfortunately, MySQL versions prior to 4.1.2 assume that characters are always eight bits (one byte), which poses some problems. To combat the issue when installing extensions we have the ability to define different SQL files for servers, that do and do not support UTF-8. In MySQL servers that do not support UTF-8, when we create fields, which define a character length, we are actually defining the length in bytes. Therefore, if we try to store UTF-8 characters that are longer than one byte, we may exceed the size of the field. To combat this, we increase the length of fields to try to accommodate UTF-8strings. For example, a varchar(20) field becomes a varchar(60) field. We triple the size of fields because, although UTF-8 characters can be more than three bytes, the majority of common characters are a maximum of three bytes. This poses another issue, if we use a varchar(100) field, scaling it up for a MySQL server, which does not support UTF-8, we would have to define it as a varchar(300) field. We cannot do this because varchar fields have a maximum size of 255. The next step is slightly more drastic. We must redefine the field type so as it will accommodate at least three hundred bytes. Therefore, a varchar(100) field becomes a text field. As an example, the core #__content table includes a field named title. For MySQL severs that support UTF-8, the field is defined as: `title` varchar(255) NOT NULL default '' For MySQL severs that do not support UTF-8, the field is defined as: `title` text NOT NULL default '' We should also be aware that using a version of MySQL that does not support UTF-8 would affect the MySQL string handling functions. For example ordering by a string field may yield unexpected results. While we can overcome this using postprocessing in our scripts using the JString class, the recommended resolution is to upgrade to the latest version of MySQL.
Read more
  • 0
  • 0
  • 1787
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-creating-simple-report-using-birt
Packt
23 Oct 2009
5 min read
Save for later

Creating a Simple Report using BIRT

Packt
23 Oct 2009
5 min read
Setting up a Simple Project The first thing we want to do when setting up our simple report project is to define what the project is going to be, and what our first simple report will be. Our first report will be a simple dump of the employees who work for Classic Cars. So, the first thing we need to do is set up a project. To do this, we will use the Navigator. Make sure you have the BIRT report perspective open. Use the following steps to create our project: Open up the Navigator by single-clicking on the Navigator tab. Right-click anywhere in the white-space in the Navigator. Select New from the menu, and under New select Project. From the Dialog screen, select Business Intelligence and Reporting Tools from the list of folders; expand that view, and select Report Project. Then click on the Next button. For the Project name, enter Class_Cars_BIRT_Reports. You can either leave the Use Default Location checkbox checked, or uncheck it and enter a location on your local drive to store this report project. Now, we have a very simple report project in which to store our BIRT reports starting with the first that we are about to create. Creating a Simple Report Now that we have our first project open, we will look at creating our first report. As mentioned earlier, we will create a basic listing report that will display all the information in the employees table. In order to do this, we will use the following steps: Right-click on the Class_Cars_BIRT_Reports project under the Navigator, and choose New and Report. Make sure the Class_Cars_BIRT_Reports project is highlighted in the new report Dialog, and enter in the name as EmployeeList.rptdesign. I chose this name as it is somewhat descriptive of the purpose of the report, which is to display a list of employees. As a rule of thumb, always try to name your reports after the expected output, such as QuarterlyEarningReport.rptdesign, weeklyPayStub.rptdesign, or accountsPayable.rptdesign. On the next screen is a list of different report templates that we can use. We will select  Simple Listing and then click on the Finish button. Go to the Data Explorer, right-click on Data Sources, and choose New Data Source. From the New Data Source Dialog box, select Classic Models Inc. Sample Database and click on the Next button. On the next screen, it will inform you of the driver information. You can ignore this for now and click Finish. Under the Data Explorer, right-click on Data Sets and choose New Data Set. On the next screen, enter the Data Set Name as dsetEmployees, and make sure that our created Data Source is selected in the list of Data sources. You can click Next when this is finished. On the Query Dialog, enter the following query and click Finish: On the next screen, just click OK. This screen is used to edit information about Data Sets, and we will ignore it for now. Now, from the Outline select Data Sets and expand it to show all of the fields. Drag the EMPLOYEENUMBER element over to the Report Designer, and drop it on the cell with the label of Detail Row. This will be the second row and the first column. You will notice that when you do this, the header row also gets an element placed in it called EMPLOYEENUMBER. This is the Header label. Double- click on this cell and it will become highlighted. We can now edit it. Type in "Employee ID". Drag and drop the LASTNAME, FIRSTNAME, and JOBTITLE to the detail cells to the right of the EMPLOYEENUMBER cell. Now, we want to put the header row in bold. Under the Outline, select the Row element located under Body/Table/Header. This will change the Property Editor. Click on Font, and then click on the Bold button. That's it! We have created our first basic report. To see what this report looks like, under the Report Designer pane, click on the Preview tab. This will allow you to get a good idea of what this report will look like. Alternatively you can actually Run the report and get an idea what this report will look like in the BIRT Report Viewer application, by going up to File/View Report/View Report in Web Viewer. This option is also available by right-click on the report design file under the Navigator, and choosing Report followed by Run. Although it may be a simple report, this exercise demonstrated how a report developer can get through the BIRT environment, and how the different elements of the BIRT perspective work together. Summary For a very simple report design, we utilized all of the major areas of the BIRT perspective. We used the Navigator to create a new report project and a new report design, the Data explorer to create out data connection and Data Set, dragged elements from the Outline to the Report Designer to get the data elements into the right place, and used the Property Editor and Outline cooperatively to bold the text in the table header.
Read more
  • 0
  • 0
  • 4572

article-image-introduction-re-host-based-modernization-using-tuxedo
Packt
23 Oct 2009
19 min read
Save for later

Introduction to Re-Host based Modernization Using Tuxedo

Packt
23 Oct 2009
19 min read
Introduction SOA enablement wraps key application interfaces in services, and integrates it into the SOA. This largely leaves the existing application logic intact, minimizing changes and adding risk only to those components that needed restructuring work to become SOA-ready. While the interfaces are modernized, without subjecting the core application components to a lot of change, the high costs and the various legacy risks associated with the mainframe platform remain. In addition, the performance and scalability of the new interfaces needs to be well-specified and tested, and the additional load they place on the system should be included in any planned capacity upgrades, potentially increasing the overall costs. Reducing or eliminating the legacy mainframe costs and risks via re-host based modernization also helps customers to fund SOA enablement, and the re-architecture phases of legacy modernization, and lay the groundwork for these steps. SOA-enabling a re-hosted application is a much easier process on an open-systems-based, SOA-ready software stack, and a more efficient one as well in terms of system resource utilization and cost. Re-architecting selected components of a re-hosted application based on specific business needs is a lower risk approach than re-architecting the entire applications en masse, and the risk can be further reduced by ensuring that target re-hosting stack provides rugged and transparent integration between re-hosted services and new components. Keeping It Real: Selective re-architecture is all about maximizing ROI by focusing re-architecture investment in the areas with the best pay-off. Undertaking a change from one language or development paradigm to another shouldn't be undertaken lightly—the investment and risks need to be well understood and justified. It is the right investment for components that require frequent maintenance changes but are difficult to maintain, because of poor /structure and layered changes. The payback on re-architecture investment will come from reducing the cost of future maintenance. Similarly, components that need significant functional changes to meet new business requirements can benefit from substantial productivity increase after re-architecture to a more modern development framework with richer tools to support future changes. The payback comes from greater business agility and time-to-market improvements. On the other hand, well-structured and maintainable COBOL components that do not need extensive changes to meet business needs will have very little return to show for the significant re-architecture investment. Leaving them in COBOL on a modern, extensible platform saves significant re-architecture costs that can be invested elsewhere, reduces risk, and shortens payback time. These considerations can help to optimize ROI for medium to large modernization projects where components measure in hundreds or thousands and contain millions or tens of millions lines of code. Re-Hosting Based Modernization For many organizations, mainframe modernization has become a matter of 'how', and not 'if'. Numerous enterprises and public sector organizations choose re-hosting as the first tangible step in their legacy modernization program precisely because it delivers the best ROI in the fastest possible manner, and accelerates the move to SOA enablement and selective re-architecture. Oracle together with our services partners provides a comprehensive re-hosting-based modernization solution that many customers have leveraged for a successful migration of selected applications or complete mainframe environments ranging from a few hundred MIPS to well over 10,000 MIPS. Two key pillars support successful re-hosting projects: Optimal target environment that lowers the Total Cost of Ownership (TCO) by 50–80 percent and maintains mainframe-class Quality of Service (QoS) using open, extensible, SOA-ready, future-proof architecture Predictable, efficient projects delivered by our SI partners with proven methodologies and automated tools Optimal target environment provided by Oracle is powered by proven open systems software stack leveraging Oracle Database and Oracle Tuxedo for a rock-solid, mainframe-class transaction processing (TP) infrastructure closely matching mainframe requirements for online applications. Mainframe-compatible Transaction Processing: Support for IBM CICS or IMS TM applications in native COBOL or C/C++ language containers with mainframe-compatible TP features. RASP: Mainframe-class performance, reliability, and scalability provided by Oracle Real Application Clusters (RAC) and Tuxedo multi-node and multi-domain clustering for load-balancing and high availability despite failure of individual nodes or network links. Workload and System Management: End-to-end transaction and service monitoring to support 24X7 operations management provided by Oracle's Enterprise Manager Grid Control and Tuxedo System and Application Monitor. SOA Enablement and Integration: Extensibility with Web services using Oracle Services Architecture Leveraging Tuxedo (SALT), J2EE integration (using WebLogic-Tuxedo Connector (WTC), Enterprise Service Bus (ESB), Portal, and BPM technologies to enable easy integration of re-hosted applications into modern Service-Oriented Architectures (SOAs). Scalable Platforms and Commodity Hardware: Scalable, Linux/UNIX-based open systems from HP, Dell, Sun, and IBM, providing: Performance on a par with mainframe systems for most workloads at significantly reduced TCO Reliability and workload management similar to mainframe installations, including physical and logical partitioning Robust clustering technologies for high availability and fail-over capabilities within a data center or across the world The diagram below shows conceptual mapping of mainframe environment to compatible open systems infrastructure: Predictable, efficient projects delivered by leading SIs and key modernization specialists use risk-mitigation methodologies, and automated tools honed over numerous projects to address a complete range of Online, Batch, and Data architectures, and the various technologies used in them. These project methodologies and automated tools that support them encompass all phases of a migration project: Preliminary Assessment Study Application Asset Discovery and Analysis Application and Data Conversion (pilot or entire application portfolio) System and Application Integration Test Engineering Regression and Performance Testing Education and Training Operations Migration Switch-Over Combining a proven target architecture stack that is well-matched to the needs of mainframe applications with mature methodologies supported by automated tools has led to a large and growing number of successful re-hosting projects. There is a rising interest to leverage the re-hosting approach to mainframe application modernization, as a way to get off a mainframe fast, and with minimal risk, in a more predictable manner for large, business-critical applications evolved over a long term and multiple development teams. Re-hosting based modernization approach preserves an organizations long term investment in critical business logic and data without risking business operations or sacrificing the QoS, while enabling customers to: Reduce or eliminate mainframe maintenance costs, and/or defer upgrade costs, saving customers 50–80 percent of their annual maintenance and operations budget Increase productivity and flexibility in IT development and operations, protecting long-term investment through application modernization Speed up and simplify application integration via SOA, without losing transactional integrity and the high performance expected by the users The rest of this article explores the critical success factors and proven transformation architecture for re-hosting legacy applications and data, describes SOA integration options and considerations when SOA-enabling re-hosted applications, highlights key risk mitigation methodologies, and provides a foundation for the financial analysis and ROI model derived from over a hundred, mainframe re-hosting projects. Critical Success Factors in Mainframe Re-Hosting Companies considering a re-hosting-based modernization strategy that involves migrating some applications off the mainframe have to address a range of concerns, which can be summarized by the following questions: How to preserve the business logic of these applications and their valuable data? How to ensure that migrated applications continue to meet performance requirements? How to maintain scalability, reliability, transactional integrity, and other QoS attributes in an open system environment? How to migrate in phases, maintaining robust integration links between migrated and mainframe applications? How to achieve predictable, cost-effective results and ensure a low-risk project? Meeting these challenges requires a versatile and powerful application infrastructure—one that natively supports key mainframe languages and services, enables automated adaptation of application code, and delivers proven, mainframe-like QoS on open system platforms. For re-hosting to enable broader aspects of the modernization strategy, this infrastructure must also provide native Web services and ESB capabilities to rapidly integrate re-hosted applications as first-class services in an SOA. Equally important is a proven, risk-mitigation methodology, automated tools, and project services specifically honed to address automated conversion and adaptation of application code and data, supported by cross-platform test engineering and execution methodology, strong system and application integration expertise, and deep experience with operations migration and switch-over. Preserving Application Logic and Data The re-hosting approach depends on a mainframe-compatible transaction processing and application services platform supporting common mainframe languages such as COBOL and C, which preserves the original business logic and data for the majority of mainframe applications and avoids the risks and uncertainties of a re-write. A complete re-hosting solution provides native support for TP and Batch programs, leveraging an application server-based platform that provides container-based support for COBOL and C/C++ application services, and TP APIs similar to IBM CICS, IMS TM, or other mainframe TP monitors. Online Transaction Processing Environment Oracle Tuxedo is the most popular TP platform for open systems, as well as leading re-hosting platform that can run most of mainframe COBOL and C applications unchanged in container-based framework that combines common application server features, including health monitoring, fail-over, service virtualization, and dynamic load balancing critical to large-scale OLTP applications together with standard TP features, including transaction management and reliable coordination of distributed transactions (a.k.a. Two-Phase Commit or XA standard). It provides the highest possible performance and scalability, and has been recently benchmarked against a mainframe at over 100,000 transactions per second, with sub-second response time. Oracle Tuxedo supports common mainframe programming languages, that is, COBOL and C, and provides comprehensive TP features compatible with CICS and IMS TM, which makes it a preferred application platform choice for re-hosting CICS or IMS TM applications with minimal changes and risks. In the Tuxedo environment, COBOL or C business logic remains unchanged. The only adaptation required is automated mapping of CICS APIs (CICS EXEC calls) to equivalent Tuxedo API functions. This mapping typically leverages a pre-processor and a mapping library implemented on Tuxedo platform, and using a full range of Tuxedo APIs. The automated nature of pre-processing and comprehensive coverage provided by the library ensures that most CICS COBOL or C programs are easily transformed into Tuxedo services. Unlike other solutions that embed this transformation in their compiler coupled with a proprietary emulation run-time, Tuxedo-based solution provides this mapping as a compiler-independent source module, which can be easily extended as needed. The resultant code uses Tuxedo API at native speed, allowing it to reach tens of thousands of transactions per second, while taking advantage of all Tuxedo facilities. In a re-hosted application CICS transactions become Tuxedo services, registered for processing by Tuxedo server processes. These services can be deployed in a single machine or across multiple machines in a Tuxedo domain (SYSPLEX-like cluster.). The services are called by front-end Java, .Net, or Tuxedo/WS clients, or UI components (tn3270 or web-based converted 3270/BMS screens), or by other services in case of transaction linking. Deferred transactions are handled by Tuxedo's/Q component, which provides in-memory and persistent queuing services. The diagram below shows Oracle Tuxedo and its surrounding ecosystem of SOA, J2EE, ESB, CORBA, MQ, and Mainframe integration components:   User Interface Migration The UI elements in these programs are typically defined using CICS Basic Mapping Support (BMS) for 3270 "green screen" terminals. While it is possible to preserve these using tn3270 emulation, many customers in re-hosting projects choose to take advantage of automated conversion of BMS macros into JSP/HTML for Web UI. Supported by a specialized Javascript library, these Web screens mimic the appearance and the behavior of "green screens" in a web browser, including tab-based navigation and PF keys. These UI components can connect to re-hosted CICS transactions running as Tuxedo services using Oracle Jolt (Java client interface for Tuxedo), Weblogic-Tuxedo Connector (WTC), or Tuxedo's Web services gateway provided by Oracle Services Architecture Leveraging Tuxedo (SALT) product. The diagram on the next page depicts a target re-hosting architecture for a typical mainframe OLTP application. The architecture uses Tuxedo services to run re-hosted CICS programs and a web application server to run re-hosted BMS UI. The servlets or JSPs containing the HTML that defines the screens, connect with Tuxedo services via Oracle Jolt, WTC, or SALT. Customers using mainframe 4GLs or languages such as PL/I or Assembler frequently choose to convert these applications to COBOL or C/C++. The adaptation of CICS or IMS TM API calls is automated through a mapping layer, which minimizes overall changes for the development team and allows them to maintain the familiar applications. For more significant extensions and new capabilities, customers incrementally leverage Tuxedo's own APIs and facilities, or leverage a tightly-linked J2EE environment provided by the WebLogic Server, and even transparently make Web services calls. The optimal extensibility options depend on application needs, availability of Java or C/COBOL skills, and other factors.   Feature or Action CICS Verb Tuxedo API Communications Area DFHCOMMAREA Typed Buffer Transaction Request LINK tpcall Transaction Return RETURN tpreturn Transfer Control XCTL tpforward Allocate Storage GETMAIN tpalloc Queues READQ / WRITEQ TD,TS /Q tpenqueue / tpdequeue Begin new transaction START TRANID /Q and TMQFORWARD Abort transaction ISSUE ABEND tpreturn TPFAIL Commit or Rollback SYNCPOINT / SYNCPOINT ROLLBACK tpcommit / tpabort     Keeping it Real:For those familiar with CICS, this is a very short example of the CICS verbs. CICS has many functions, most of which either map natively to a similar Tuxedo API or are provided by migration specialists based on their extensive experience with such migrations. In summary, Tuxedo provides a popular platform for deploying, executing, and managing COBOL and C re-hosted transactional applications requiring any of the following OLTP and infrastructure services: Native, compiler-independent support for COBOL, C, or C++ Rich set of infrastructure services for managing and scaling diverse workloads Feature-set compatibility and inter-operability with IBM CICS and IMS/TM Two-Phase Commit (2PC) for managing transactions across multiple application domains and XA-compliant resource managers (databases, message queues) Guaranteed inter-application messaging and transactional queuing Transactional data access (using XA-compliant resource managers) with ACID qualities Services virtualization and dynamic load balancing Centralized management of multiple nodes in a domain, and across multiple domains Communications gateways for multiple traditional and modern communication protocols SOA Enablement through native Web services and ESB integration Workload Monitoring and Management An important aspect of the mainframe environment is workload monitoring and management, which provides information for effective performance analysis and capabilities that enable mainframe systems to achieve better throughput and responsiveness. Oracle's Tuxedo System and Application Monitor (TSAM) provides similar capabilities too. Define monitoring policies and patterns based on application requests, services, system servers such as gateways, bridges, and XA-defined stages of a distributed transaction Define SLA thresholds that can trigger a variety of events within Tuxedo event services including notifications, and instantiation of additional servers Monitor transactions on an end-to-end basis from a client call through all services across all domains involved in a client request Collect service statistics for all infrastructure components such as servers and gateways Detail time spent on IPC queues, waiting on network links, and time spent on subordinate services TSAM provides a built-in, central, web-based management and monitoring console, and an open framework for integration with third-party performance management tools. Batch Jobs Mainframe batch jobs are a response to a human 24-hour clock on which many businesses run. It includes beginning-of-period or end-of-period (day, week, month, quarter) processing for batched updates, reconciliation, reporting, statement generation, and similar applications. In some industries, external events tied to a fixed schedule such as intra-day, opening or closing trade in a stock exchange, drive specific processing needs. Batch applications are an equally important asset, and often need to be preserved and migrated as well. The batch environment uses Job Control Language (JCL) jobs managed and monitored by JES2 or JES3 (Job Entry System), which invoke one or more programs, access and manipulate large datasets and databases using sort and other specialized utilities, and often run under the control of a job scheduler such as CA-7/CA-11. JCL defines a series of job steps—a sequence of programs and utilities, specifies input and output files, and provides exception handling. Automated parsing and translation of JCL jobs to UNIX scripts such as Korn shell (ksh) or Perl, enables the overall structure of the job to remain the same, including job steps, classes, and exception handling. Standard shell processing is supplemented with required utilities such as SyncSort, and support for Generation Data Group (GDG) files. REXX/CLIST/PROC scripting environments on the mainframe are similarly converted to ksh or other scripting languages. Integration with Oracle Scheduler, or other job schedulers running in UNIX/Linux or Windows provides a rich set of calendar and event-based scheduling capabilities as well as dependency management similar to mainframe schedulers. In some cases, reporting done via batch jobs can be replaced using standard reporting packages such as Oracle BI Publisher. The diagram below shows a typical target re-hosting architecture for batch. It includes a scheduler to control and trigger batch jobs, scripting framework to support individual job scripts, and an application server execution framework for the batch COBOL or C programs. Unlike other solutions that run these programs directly as OS processes without the benefit of application server middleware, Oracle recommends using container-based middleware to provide higher reliability, availability, and monitoring to the batch programs. The target batch programs invoked by the scripts can also run directly as OS processes, but if mainframe-class management and monitoring similar to JES2 or JES3 environment is a requirement, these programs can run as services under Tuxedo, benefiting from the health monitoring, fail-over, load balancing, and other application server-like features it provides. Files and Databases When moving platforms (mainframe to open systems), the application and data have to be moved together. Data schemas and data stores need to be moved in a re-hosted mainframe modernization project just as with a re-architecture. The approach taken depends on the source data store. DB2 is the most straightforward, since DB2 and Oracle are both relational databases. In addition to migrating the data, customers sometimes choose to perform data cleansing, field extensions, merge columns, or other data maintenance practices leveraging the automated tooling that synchronizes all data changes with changes to the application's data access code. Mainframe DB2 DB2 is a predominant relational database on IBM mainframes. When migrating to Oracle Database, the migration approach is highly automated, and resolves all discrepancies between the two RDBMS in terms of field formats as well as error codes returned to applications, so as to maintain application behavior unchanged, including stored procedures if any. IMS IMS/DB (also known as DL/1) is a popular hierarchical database for older applications. Creating appropriate relational data schema for this data requires an understanding of the application access patterns so as to optimize the schema for best performance based on the most frequent access paths. To minimize code impact, a translation layer can be used at run-time to support IMS DB style data access from the application, and map it to appropriate SQL calls. This allows the applications to interface with the segments, now translated as DB2 UDB or ORACLE tables, without impacting application code and maintenance. VSAM VSAM files are used for keyed-sequential data access, and can be readily migrated to ISAM files or to Oracle Database tables wherever transactional integrity is required (XA features). Some customers also choose to migrate VSAM files to Oracle Database to provide accessibility from other distributed applications, or to simplify the re-engineering required to extend certain data fields or merge multiple data sources. Meeting Performance and Other QoS Requirements The mainframe's performance, reliability, scalability, manageability, and other QoS attributes have earned it pre-eminence for business-critical applications. How well do re-hosting solutions measure up against these characteristics? Earlier solutions based on IBM CICS emulators derived from development tools often did not measure up to the demands of mainframe workloads since they were never intended for true production environment and have not been exposed to large-scale applications. As a result, they have only been used for re-hosting small systems under 300 MIPS and not requiring any clustering or distributed workload handling. Oracle Tuxedo was built to scale ground up, to support high performance telecommunications operations. It has the distinction of being the only non-mainframe TP solution recognized for its mainframe-like performance, reliability, and QoS characteristics. Most large enterprise customers requiring such capabilities in distributed systems have traditionally relied on Tuxedo. Consistently rated by IDC and Gartner as the market leader, and predominant in non-mainframe OLTP applications, it has also become the preferred COBOL/C application platform and transaction engine for re-hosted mainframe applications requiring high performance and/or mission-critical availability and reliability. Reasons for the broad recognition of Tuxedo as the only mainframe-class application platform and transaction engine for distributed systems are based on mainframe-class performance, scalability, reliability, availability, and other QoS attributes proven in multiple customer deployments. The following table highlights some of these capabilities:   Reliability Availability Guaranteed messaging and transactional integrity Hardened code from 25 years of use in the world's largest transaction applications Transaction integrity across systems and domains through a two phase commit (XA) for all resources such as databases, queues, and so on. Proven in mainframe-to-mainframe transactions and messaging No single point of failure, 99.999% uptime with N+1/N+2 clusters Application services upgradeable in operation Self-monitoring, automated fail-over, datadriven routing for super high availability Centralized monitoring and management with clustered domains; automated, lights-out operations     Workload Management   Performance and Scalability   Resource management and prioritization across Tuxedo services Dynamic load balancing across domains based on load conditions Data-driven routing enables horizontally distributed database grids and differentiated QoS End-to-end monitoring of Tuxedo system and application services enables SLA enforcement Virtualization support enables spawning of Tuxedo servers on demand Parallel processing to maximize resource utilization with low latency code paths that provide sub-second response at any load Horizontal and vertical scaling of system resources yields linear performance increases Request multiplexing (synchronous and asynchronous) maximizes CPU utilization Proven in credit card authorizations at over 13.5K tps, and in telco billing at over 56K tps. Middleware of choice in HP, Fujitsu, Sun, IBM, and NEC TPC-C benchmarks    
Read more
  • 0
  • 0
  • 3006

article-image-catalyst-web-framework-building-your-own-model
Packt
23 Oct 2009
12 min read
Save for later

Catalyst Web Framework: Building Your Own Model

Packt
23 Oct 2009
12 min read
Extending a DBIx::Class Model A common occurrence is a situation in which your application has free reign over most of the database, but needs to use a few stored procedure calls to get at certain pieces of data. In that case, you'll want to create a normal DBIC schema and then add methods for accessing the unusual data. As an example, let's look back to the AddressBook application and imagine that for some reason we couldn't use DBIx::Class to access the user table, and instead need to write the raw SQL to return an array containing everyone's username. In AddressBook::Model::AddressDB, we just need to write a subroutine to do our work as follows:     package AddressBook::Model::AddressDB;    // other code in the package    sub get_users {        my $self = shift;        my $storage = $self->storage;        return $storage->dbh_do(            sub {                my $self = shift;                my $dbh = shift;                my $sth = $dbh->prepare('SELECT username FROM user');                $sth->execute();                my @rows = @{$sth->fetchall_arrayref()};                return map { $_->[0] } @rows;                });    } Here's how the code works. On the first line, we get our DBIC::Schema object and then obtain the schema's storage object. The storage object is what DBIC uses to execute its generated SQL on the database, and is usually an instance of DBIx:: Class::Storage::DBI. This class contains a method called dbh_do which will execute a piece of code, passed to dbh_do as a coderef (or "anonymous subroutine"), and provide the code with a standard DBI database handle (usually called $dbh). dbh_do will make sure that the database handle is valid before it calls your code, so you don't need to worry about things like the database connection timing out. DBIC will reconnect if necessary and then call your code. dbh_do will also handle exceptions raised within your code in a standard way, so that errors can be caught normally. The rest of the code deals with actually executing our query. When the database handle is ready, it's passed as the second argument to our coderef (the first is the storage object itself, in case you happen to need that). Once we have the database handle, the rest of the code is exactly the same as if we were using plain DBI instead of DBIx::Class. We first prepare our query (which need not be a SELECT; it could be EXEC or anything else), execute it and, finally, process the result. The map statement converts the returned data to the form we expect it in, a list of names (instead of a list of rows each containing a single name). Note that the return statement in the coderef returns to dbh_do, not to the caller of get_users. This means that you can execute dbh_do as many times as required and then further process the results before returning from the get_users subroutine. Once you've written this subroutine, you can easily call it from elsewhere in your application:     my @users = $c->model('AddressDB')->get_users;    $c->response->body('All Users' join ', ', @users); Custom Methods Without Raw SQL As the above example doesn't use any features of the database that DBIC doesn't explicitly expose in its resultset interface, let us see how we can implement the get_users function without using dbh_do. Although the preconditions of the example indicated that we couldn't use DBIC, it's good to compare the two approaches so you can decide which way to do things in your application. Here's another way to implement the above example:     sub get_users { # version 2        my $self = shift;        my $users = $self->resultset('User');        my @result;        while(my $user = $users->next){                push @result, $user->username;        }        return @result;    } This looks like the usual DBIC manipulation that we're used to. (Usually we call $c->model('AddressDB::User') to get the "User" resultset, but under the hood this is the same as $c->model('AddressDB')->resultset('User'). In this example, $self is the same as $c->model('AddressDB').) The above code is cleaner and more portable (across database systems) than the dbh_do method, so it's best to prefer resultsets over dbh_do unless there's absolutely no other way to achieve the functionality you desire. Calling Database Functions Another common problem is the need to call database functions on tables that you're accessing with DBIC. Fortunately, DBIC provides syntax for this case, so we won't need to write any SQL manually and run it with dbh_do. All that's required is a second argument to search. For example, if we want to get the count of all users in the user table, we could write (in a controller) the following:     $users = $c->model('AddressDB::User');    $users->search({}, { select => [ { COUNT => 'id' } ],                                                    as => [ 'count' ],});    $count = $users->first->get_column('count'); This is the same as executing SELECT COUNT(id) FROM user, fetching the first row and then setting $count to the first column of that row. Note that we didn't specify a WHERE clause, but if we wanted to, we could replace the first {} with the WHERE expression, and then get the count of matching rows. Here's a function that we can place in the User ResultSetClass to get easy access to the user count:     sub count_users_where {        my $self = shift;        my $condition = shift;        $self->search($condition,                { select => [ { COUNT => 'id' } ],                        as => [ 'count' ], });        my $first = $users->first;        return $first->get_column('count') if $first;        return 0; # if there is no "first" row, return 0    } Now, we can write something like the following:     $jons = $c->model('AddressDB::User')->        count_users_where([ username => {-like => '%jon%'}]); to get the number of jons in the database, without having to fetch every record and count them. If you only need to work with a single column, you can also use the DBIx::Class:: ResultSetColumn interface. Creating a Database Model from Scratch In some cases, you'll have no use for any of DBIC's functionality. DBIC might not work with your database, or perhaps you're migrating a legacy application that has well-tested database queries that you don't want to rewrite. In this sort of situation, you can write the entire database model manually. In the next example, we'll use Catalyst::Model::DBI to set up the basic DBI layer and the write methods (like we did above) to access the data in the model. As we have the AddressBook application working, we'll add a DBI model and write some queries against the AddressBook database. First, we need to create the model. We'll call it AddressDBI: $ perl script/addressbook_create.pl model AddressDBI DBI DBI:SQLite: database When you open the generated AddressBook::Model::AddressDBI file, you should see something like this:     package AddressBook::Model::AddressDBI;    use strict;    use base 'Catalyst::Model::DBI';    __PACKAGE__->config(            dsn => 'DBI:SQLite:database',            user => '',            password => '',            options => {},    );    1; # magic true value required Once you have this file, you can just start adding methods. The database handle will be available via $self->dbh, and the rest is up to you. Let's add a count_users function:     sub count_users {        my $self = shift;        my $dbh = $self->dbh;        my $rows = $dbh->            selectall_arrayref('SELECT COUNT(id) FROM user');        return $rows->[0]->[0]; # first row, then the first column    } Let's also add a test Controller so that we can see if this method works. First, create the Test controller by running the following command line: $ perl script/addressbook_create.pl controller Test And then add a quick test action as follows:     sub count_users : Local {        my ($self, $c) = @_;        my $count = $c->model('AddressDBI')->count_users();        $c->response->body("There are $count users."); } You can quickly see the output of this action by running the following command line:   $ perl script/addressbook_test.pl /test/count_users  There are 2 users. The myapp_test.pl script will work for any action, but it works best for test actions like this because the output is plain-text and will fit on the screen. When you're testing actual actions in your application, it's usually easier to read the page when you view it in the browser. That's all there is to it—just add methods to AddressDBI until you have everything you need. The only other thing you might want to do is to add the database configuration to your config file. It works almost the same way for DBI as it does for DBIC::Schema:     ---    name: AddressBook    Model::AddressDBI:        dsn: "DBI:SQLite:database"        username: ~        password: ~            options:                option1: something                # and so on    # the rest of your config file goes here Implementing a Filesystem Model In this final example, we'll build an entire model from scratch without even the help of a model base class like Catalyst::Model::DBI. Before you do this for your own application, you should check the CPAN to see if anyone's done anything similar already. There are currently about fifty ready-to-use model base classes that abstract data sources like LDAP servers, RSS readers, shopping carts, search engines, Subversion, email folders, web services and even YouTube. Expanding upon one of these classes will usually be easier than writing everything yourself. For this example, we'll create a very simple blog application. To post the blog, you just write some text and put it in a file whose name is the title you want on the post. We'll write a filesystem model from scratch to provide the application with the blog posts. Let's start by creating the app's skeleton:   $ catalyst.pl Blog After that, we'll create our Filesystem model:   $ cd Blog  $ perl script/blog_create.pl model Filesystem We'll also use plain TT for the View:   $ perl script/blog_create.pl view TT TT
Read more
  • 0
  • 0
  • 2456

article-image-customizing-drupal-6-interface
Packt
23 Oct 2009
19 min read
Save for later

Customizing Drupal 6 Interface

Packt
23 Oct 2009
19 min read
There is quite a lot involved in coming up with an entirely fresh, pleasing, and distinct look for a site. There are lots of fiddly little bits to play around with, so you should be prepared to spend some time on this section after all, a site's look and feel is really the face you present to the community, and in turn, the face of the community presents to the outside world. Take some time to look at what is already out there. Many issues that you will encounter while designing a site have already been successfully dealt with by others, and not only by Drupal users of course. Also, don't be scared to treat your design as an ongoing process while it is never good to drastically change sites on a weekly basis, regular tweaking or upgrading of the interface can keep it modern and looking shiny new. Planning a Web-Based Interface The tenet form follows function is widely applied in many spheres of human knowledge. It is a well understood concept that states the way something is built or made must reflect the purpose it was made for. This is an exceptionally sensible thought, and applying it to the design of your site will provide a yardstick to measure how well you have designed it. That's not to say one site should look like every other site that performs the same function. In fact, if anything, you want to make it as distinctive as possible, without stepping over the bounds of what the target user will consider good taste or common sense. How do you do that? The trick is to relate what you have or do as a website with a specific target audience. Providing content that has appeal to both sexes of all ages across all nationalities, races, or religions implies that you should go with something that everyone can use. If anything, this might be a slightly flavourless site because you wouldn't want to marginalize any group of users by explicitly making the site bias towards another group. Luckily though, to some extent your target audience will be slightly easier to define than this, so you can generally make some concessions for a particular type of user. Visual Design There's no beating about the bush on this issue. Make the site appear as visually simple as possible without hiding any critical or useful information. By this, I mean don't be afraid to leave a fairly large list of items on a page if all the items on that list are useful, and will be (or are) used frequently. Hiding an important thing from users no matter how easy it appears to be to find it on other pages will frustrate them, and your popularity might suffer. How a site looks can also have a big impact on how users understand it to work. For example, if several different fonts apply to different links, then it is entirely likely that users will not think of clicking on one type of link or another because of the different font styles. Think about this yourself for a moment, and visualize whether or not you would spend time hovering the pointer over each and every type of different content in the hope that it was a link. This can be summed up as: Make sure your site is visually consistent, and that there are no style discrepancies from one page to the next. By the same token, reading a page of text where the links are given in the same font and style as the writing would effectively hide that functionality. There are quite a few so-called rules of visual design, which can be applied to your site. Some that might apply to you are: the rule of thirds, which states that things divided up into thirds either vertically or horizontally are more visually appealing than other designs; or the visual center rule, which states that the visual center of the page (where the eye is most attracted to) is just above and to the right of the actual center of the page. You may wish to visit the website A List Apart at http://www.alistapart.com/ that has plenty of useful articles on design for the Web, or try searching on Google for more information. Language Now this is a truly interesting part of a site's design, and the art of writing for the Web is a lot more subtle than just saying what you mean. The reason for this is that you are no longer writing simply for human consumption, but also for consumption by machines. Because machines can only follow a certain number of rules when interpreting a page, the concessions on the language used must be made by the writers (if they want their sites to feature highly on search engines). Before making your site's text highly optimized for searching, there are a few more fundamental things that are important to consider. First off, make sure your language is clear and concise. This is the most important; rather sacrifice racy, stylized copy for more mundane text if the mundane text is going to elucidate important points better. People have very short attention spans when it comes to reading Web copy so keep things to the point. Apart from the actual content of your language, the visual and structural appearance of the copy is also important. Use bold or larger fonts to emphasize headings or important points, and ensure that text is spaced out nicely to make the page easier on the eye, and therefore easier to read and understand. Images Working with images for the Web is very much an art. I don't mean this in the sense that generally one should be quite artistic in order to make nice pictures. I mean that actually managing and dealing with image files is itself an art. There is a lot of work to be done for the aspiring website owner with respect to attaining a pleasing and meaningful visual environment. This is because the Web is an environment that is most reliant on visual images to have an effect on users because sight and sound are the only two senses that are targeted by the Internet (for now). In order to have the freedom to manipulate images, you really need to use a reasonably powerful image editor. Gimp, http://www.gimp.org/, is an example of a good image-editing environment, but anything that allows you to save files in a variety of different formats and provides resizing capabilities should be sufficient. If you have to take digital photographs yourself, then ensure you make the photos as uniform as possible, with a background that doesn't distract from the object in question editing the images to remove the background altogether is probably best. There are several areas of concern when working with images, all of which need to be closely scrutinized in order to produce an integrated and pleasing visual environment: One of the biggest problems with images is that they take up a lot more space and bandwidth than text or code. For this reason, having an effective method for dealing with large images is required—simply squashing large images into thumbnails will slow everything down because the server still has to download the entire large file to the user's machine. One common mistake people make when dealing with images is not working on them early on in the process to make them as uniform in size and type as possible. If all the images are of one size and of the same dimension, then you are going to have things a lot easier than most. In fact, this should really be your aim before doing anything involving the site—make sure your images are all as uniform as a given situation allows. Deciding what type of image you actually want to use from the variety available can also be a bit of an issue because some image types take up more space than others, and some may not even be rendered properly in a browser. By and large, there are really only three image types that are most commonly used—GIF, PNG, and JPG. The intended use of an image can also be a big factor when deciding how to create, size, and format the file. For example, icons and logos should really be saved as PNG or GIF files, whereas photos and large or complex images should be saved in the JPG format due to how efficiently JPG handles complex images. Let's take a quick look at those here. GIF, or Graphics Interchange Format, is known for its compression and the fact that it can store and display multiple images. The major drawback to GIF is that images can only display up to 256 distinct colors. For photographic-quality images, this is a significant obstacle. However, you should use GIFs for: Images with a transparent background Animated graphics Smaller, less complex images requiring no more than 256 colors PNG, or Portable Network Graphics, is actually designed as a replacement for GIF files. In general, it can achieve greater file compression, give a wider range of color depth, and quite a bit more. PNG, unlike GIF files, does not support animations. You can use PNG files for anything that you would otherwise use GIFs for, with the exception of animations. IE6 will not render transparency in PNG images correctly, so be aware that this may affect what people think about your site having ugly shaded regions around images can make your site appear to be of poor quality when in fact it is an aspect of their dated browser that causes the problem. Incidentally, there is also an MNG format that allows for animations you might want to check that out as an alternative to animated GIFs. JPG, or JPEG (Joint Photographic Experts Group), should be used when presenting photo-realistic images. JPG can compress large images while retaining the overall photographic quality. JPG files can use any number of colors, and so it's a very convenient format for images that require a lot of color. JPG should be used for: Photographs Larger, complex images requiring more than 256 to display properly Be aware that JPG uses lossy compression, which means that in order to handleimages efficiently, the compression process loses quality. Before we begin an in-depth look at themes that are responsible for just about everything when it comes to your site's look-and-feel, we will take a glance at CSS. CSS The pages in a Drupal site obtain their style-related information from associated stylesheets that are held in their respective theme folders. Using stylesheets gives designers excellent, fine-grained control over the appearance of web pages, and can produce some great effects. The appearance of pretty much every aspect of the site can be controlled from CSS within a theme, and all that is needed is a little knowledge of fonts, colors, and stylesheet syntax. It will make life easier if you have a ready-made list of the type of things you should look at setting using the stylesheet. Here are the most common areas (defined by HTML elements) where stylesheets can be used to determine the look-and-feel of a site's: Background Text Font Color Images Border Margin Padding Lists Besides being able to change all these aspects of HTML, different effects can be applied depending on whether certain conditions, like a mouse hovering over the specified area, are met this will be demonstrated a little later on. You can also specify attributes for certain HTML tags that can then be used to apply styles to those specific tags instead of creating application-wide changes. For example, imagine one paragraph style with a class attribute set, like this: <p class="signature"></p> You could reference this type of paragraph in a stylesheet explicitly by saying something like: p.signature {color: green;} Analyzing this line highlights the structure of the standard style-sheet code block in the form of a: Selector: in this case p.signature Property: in this case color Delimiter: always : Value: in this case green Note that all the property/value pairs are contained within curly braces, and each is ended with a semi-colon. It is possible to specify many properties for each selector, and indeed we are able to specify several selectors to have the same properties. For example, the following block is taken from the garland stylesheet, style.css, and is used to provide all the header text within the theme with a similar look-and-feel by giving them all the same properties: h1, h2, h3, h4, h5, h6 {margin: 0;padding: 0;font-weight: normal;font-family: Helvetica, Arial, sans-serif;} In this instance, multiple selectors have been specified in a comma delimited list, with each selector given four properties to control the margin, padding, font-weight, and font-family of the header tags. It is important to realize that tags can be referenced using either the class attribute, or the id attribute, or both. For example, the following HTML: <p class="signature" id="unique-signature"></p> ...makes it possible for this tag to be referenced both as part of a class of tags all with the same property, or specifically by its unique id attribute. The distinction between the two is important because class gives broad sweeping powers to make changes to all tags within that class, and id gives fine-grained control over a tag with the unique id. This introduction to CSS has been very brief, and there are plenty of excellent resources available. If you would like to learn more about CSS (and it is highly recommended), then visit: CSS Discuss: http://css-discuss.incutio.com/ HTML Dog: http://www.htmldog.com/ We are ready to begin looking at… Themes The use of themes makes Drupal exceptionally flexible when it comes to working with the site's interface. Because the functionality of the site is by and large decoupled from the presentation of the site, it is quite easy to chop and change the look, without having to worry about affecting the functionality. This is obviously a very useful feature because it frees you up to experiment knowing that if worst comes to worst, you can reset the default settings and start from scratch. You can think of a theme as a template for your site that can be modified in order to achieve virtually any design criteria. Of course, different themes have wildly varying attributes; so it is important to find the theme that most closely resembles what you are looking for in order to reduce the amount of work needed to match it to your envisaged design. Also, different themes are implemented differently. Some themes use fixed layouts with tables, while others use div tags and CSS you should play around with a variety of themes in order to familiarize yourself with a few different ways of creating a web page. We only have space to cover one here, but the lessons learned are easily transferred to other templates with a bit of time and practice. Before we go ahead and look at an actual example, it is important to get an overview of how themes are put together in general. Theme Anatomy Some of you might have been wondering what on earth a theme engine is, and how both themes and theme engines relate to a Drupal site. The following two definitions should clear up a few things: Theme: A file or set of files that defines and controls the features of Drupal's web pages (ranging from what functionality to include within a page, to how individual page elements will be presented) using PHP, HTML, CSS and images. Theme engine: Provides PHP-based functionality to create your own unique theme, which in turn, gives excellent control over the all aspects of a Drupal site. Drupal ships with the PHPTemplate engine that is utilized by most themes. Not all theme engines are pure PHP-based. For example, there is a Smarty theme engine available in Drupal for use by people who are familiar with Smarty templates. Looking at how theme files are set up within Drupal hints at the overall process and structure of that theme. Bear in mind that there are several ways to create a working theme, and not all themes make use of template files, but in the case of the Drupal's default theme setup, we have the following: The left-hand column shows the folders contained within the themes directory. There are a number of standard themes, accompanied by the engines folder that houses a phptemplate.engine file, to handle the integration of templates into Drupal's theming system. Looking at the files present in the garland folder, notice that there are a number of PHPTemplate files suffixed by .tpl.php. These files make use of HTML and PHP code to modify Drupal's appearance the default versions of these files, which are the ones that would be used in the event a theme had not implemented its own, can be found in the relevant modules directory. For example, the default comment.tpl.php file is found in modules/comment, and the default page.tpl.php file is located, along with others, in the modules/system folder. Each template file focuses on its specific page element or page, with the noted exception of template.php that is used to override non-standard theme functions i.e. not block, box, comment, node or page. The theme folder also houses the stylesheets along with images, and in the case of the default theme, colors. What's interesting is the addition of the mandatory .info file (.info files were present in Drupal 5 modules, but are only mandatory in themes for Drupal 6) that contains information about the theme to allow Drupal to find and set a host of different parameters. Here are a few examples of the type of information that the .info file holds: Name - A human readable theme name Description—A description of the theme Core—The major version of Drupal that the theme is compatible with Regions—The block regions available to the theme Features—Enables or disables features available in the theme—for example, slogan or mission statement Stylesheets—Stipulate which stylesheets are to be used by the theme Scripts—Specify which scripts to include PHP—Define a minimum version of PHP for which the theme will work To see how .info files can be put to work, look closely at the Minnelli theme folder. Notice that this is in fact a sub-theme that contains only a few images and CSS files. A sub-theme shares its parents' code, but modifies parts of it to produce a new look, new functionality or both. Drupal allows us to create new sub-themes by creating a new folder within the parent theme (in this case, Garland), and providing, amongst other things, new CSS. This is not the only way to create a subtheme a subtheme does not have to be in a subdirectory of its parent theme, rather it can specify the base theme directive in its .info file, in order to extend the functionality of the specified base, or parent, theme. As an exercise, access the Minnelli .info file and confirm that it has been used to specify the Minnelli stylesheet. So far we have only looked at templated themes, but Drupal ships with a couple of CSS driven themes that do not rely on the PHPTemplate engine, or any other, at all. Look at the chameleon theme folder: Notice that while it still has the mandatory .info file, a few images, and stylesheets, it contains no .tpl.php files. Instead of the template system, it uses the chameleon.theme file that implements its own versions of Drupal's themeable functions to determine the theme's layout. In this case, the Marvin theme is a nice example of how all themes can have sub-themes in the same way as the template-driven theme we saw earlier. It should be noted that engine-less themes are not quite as easy to work with as engine-based themes, because any customization must be done in PHP rather than in template files. In a nutshell, Drupal provides a range of default themeable functions that expose Drupal's underlying data, such as content and information about that content. Themes can pick and choose which snippets of rendered content they want to override the most popular method being through the use of PHP template files in conjunction with style sheets and a .info file. Themes and sub-themes are easily created and modified provided that you have some knowledge of CSS and HTML PHP helps if you want to do something more complicated. That concludes our brief tour of how themes are put together in Drupal. Even if you are not yet ready to create your own theme, it should be clear that this system makes building a new theme fairly easy, provided one knows a bit about PHP. Here's the process: Create a new themes folder in the sites/default directory and add your new theme directory in there call it whatever you want, except for a theme name that is already in use. Copy the default template files (or files from any other theme you want to modify) across to the new theme directory, along with any other files that are applicable (such as CSS files). Modify the layout (this is where your PHP and HTML skills come in handy) and add some flavor with your own stylesheet. Rewrite the .info file to reflect the attributes and requirements of the new theme. Now, when it is time for you to begin doing a bit of theme development, bear in mind that there are many types of browser, and not all of them are created equal. What this means is that a page that is rendered nicely on one browser might look bad, or worse, not even function properly on another. For this reason, you should test your site using several different browsers! The Drupal help site has this to say about browsers: It is recommended you use the Firefox browser with developer toolbar and the 'view formatted source' extensions. You can obtain a copy of the Firefox browser at http://www.mozilla.com/firefox/ if you wish to use something other than Internet Explorer. Firefox can also be extended with Firebug, which is an extremely useful tool for client-side web debugging. For the purposes of this article, we are going to limit ourselves to the selection of a base theme that we will modify to provide us with the demo site's new interface. This means that, for now, you don't have to concern yourself with the intricacies of PHP.
Read more
  • 0
  • 0
  • 1480
article-image-python-ldap-applications-part-4-ldap-schema
Packt
23 Oct 2009
8 min read
Save for later

Python LDAP Applications: Part 4 - LDAP Schema

Packt
23 Oct 2009
8 min read
Using Schema Information As with most LDAP servers, OpenLDAP provides schema access to LDAP clients. An LDAP schema defines object classes, attributes, matching rules, and other LDAP structures. In this article, we will take a brief look at what might be the most complex module in the Python-LDAP API, the ldap.schema module. This module provides programmatic access to the schema, using the LDAP subschema record, and the subschema's subentries obtained from the LDAP server. The module has two major components. The first is the SubSchema object, which contains the schema definition, and provides numerous functions for navigating through the definitions stored in the schema. The second component is the model, which contains classes that describe structural components (Schema Elements) of the schema. For example, the model contains classes like ObjectClass, AttributeType, MatchingRule, and DITContentRule. Getting the Schema from the LDAP Server The ldap.schema module does not automatically retrieve the schema information. It must be fetched from the server with an LDAP search operation. The schema is always stored in a specific entry, almost always accessible with the DN cn=subschema. (If it is elsewhere, and is accessible, the Root DSE will note the location.) We can retrieve the record by doing a search with a base scope: >>> res = l.search_s('cn=subschema',... ldap.SCOPE_BASE,... '(objectclass=*)',... ['*','+']... )>>> subschema_entry = ldaphelper.get_search_results(res)[0]>>> subschema_subentry = subschema_entry.get_attributes()>>> The search configuration above should return only one record – the record for cn=subschema. Because most of the schema attributes are operational attributes, we need to specify, in the list of attributes, both * for all regular attributes and + for all operational attributes. The ldaphelper.get_search_results() function we created early in this series returns a list of LDAPSearchResult objects. Since we know that we want the first one (in a list of one), we can use the [0] notation at the end to return just the first item in the resulting list. Now, schema_entry contains the LDAPSearchResult object for the cn=subschema record. We need the list of attributes – namely, the schema-defining attributes, usually called the subschema subentry. We can use the get_attributes() method to retrieve the dict of attributes. Now we have the information necessary for creating a new SubSchema object. The SubSchema Object The SubSchema object provides access to the details of the schema definitions. The SubSchema() constructor takes one parameter: a dictionary of attributes that contains the subschema subentry information. This is the information we retrieved and stored in the subschema_subentry variable above. Creating a new SubSchema object is done like this: >>> subschema = ldap.schema.SubSchema( subschema_subentry )>>> Now we can access the schema information. We can, for instance, get the schema information for the cn attribute: >>> cn_attr = subschema.get_obj( ldap.schema.AttributeType, 'cn' )>>> cn_attr.names('cn', 'commonName')>>> cn_attr.desc'RFC2256: common name(s) for which the entity is known by'>>> cn_attr.oid'2.5.4.3'>>> The first line employs the get_obj() method to retrieve an AttributeType object. The call to get_obj() above uses two parameters. The first is the class (a subclass of SchemaElement) that represents an attribute. This is ldap.schema.AttributeType. If we were getting an object class instead of an attribute, we would use the same method, but pass an ldap.schema.ObjectClass as the first parameter. The second parameter is a string name (or OID) of the attribute. We could have used 'commonName' or '2.5.4.3' and attained the same result. The cn_attr object (an instance of an AttributeType class) has a number of properties representing schema statements. For example, in the example above, the names property contains a tuple of the attribute names for that attribute, and the desc property contains the value of the description, as specified in the schema. The oid attribute contains the Object Identifier (OID) for the CN attribute. Let's look at one more method of the SubSchema class before moving on to the final script in this article. Using the attribute_types() method of the SubSchema class, we can find out what attributes are required for an record, and what attributes are allowed. For example, consider a record that has the object classes account and simpleSecurityObject. The uid=authenticate,ou=system,dc=example,dc=com entry in our directory information tree is an example of such a user. We can use the attribute_types() method to get information about what attributes this record can or must have: >>> oc_list = ['account', 'simpleSecurityObject']>>> oc_attrs = subschema.attribute_types( oc_list )>>> must_attrs = oc_attrs[0]>>> may_attrs = oc_attrs[1]>>> >>> for ( oid, attr_obj ) in must_attrs.iteritems():... print "Must have %s" % attr_obj.names[0]... Must have userPasswordMust have objectClassMust have uid>>> for ( oid, attr_obj ) in may_attrs.iteritems():... print "May have %s" % attr_obj.names[0]... May have oMay have ouMay have seeAlsoMay have descriptionMay have lMay have host>>> The oc_list list has the names of the two object classes in which we are interested: account and simpleSecurityObject. Passing this list to the attribute_types() method, we get a two-item tuple. The first item in the tuple is a dictionary of required attributes. The key in the dictionary is the OID: >>> must_attrs.keys()['2.5.4.35', '2.5.4.0', '0.9.2342.19200300.100.1.1']>>> The value in the dictionary is an AttributeType object corresponding to the attribute defined for the OID key: >>> must_attrs['2.5.4.35'].oid'2.5.4.35'>>> In the code snippet above, we assigned each value in the two-item tuple to a different variable: must_attrs contains the first item in the tuple – the dictionary of must-have attributes. The may_attrs contains a dictionary of the attributes that are allowed, but not required. Iterating through the dictionaries and printing the output, we can see that the required attributes for a record that used both the account and the simpleSecurityObject object classes would be userPassword, objectclass, and uid. Several other attributes are allowed, but not required: o, ou, seeAlso, description, l, and host. We could find out which object class definitions required or allowed which of these attributes using the get_obj() method we looked at above: >>> oc_obj = subschema.get_obj( ldap.schema.ObjectClass, 'account' )>>> oc_obj.may('description', 'seeAlso', 'localityName', 'organizationName', 'organizationalUnitName', 'host')>>> oc_obj.must('userid',)>>>>>> oc_obj = subschema.get_obj( ldap.schema.ObjectClass,... 'simpleSecurityObject' )>>> oc_obj.must('userPassword',)>>> oc_obj.may()>>> From the above, we can see that most of the required and optional attributes come from the account definition, while only userPassword comes from the simpleSecurityObject definition. The requirement of the objectClass attribute comes from the top object class, the ultimate ancestor of all structural object classes. The schema support offered by the Python-LDAP API makes it possible to program schema-aware clients that can, for instance, perform client-side schema checking, dynamically build forms for creating records, or compare definitions between different LDAP servers on a network. Unfortunately, the ldap.schema module is poorly documented. With most of the module, the best source of information is the __doc__ strings embedded in the code: >>> print ldap.schema.SubSchema.attribute_types.__doc__ Returns a 2-tuple of all must and may attributes including all inherited attributes of superior object classes by walking up classes along the SUP attribute. The attributes are stored in a ldap.cidict.cidict dictionary. object_class_list list of strings specifying object class names or OIDs attr_type_filter list of 2-tuples containing lists of class attributes which has to be matched raise_keyerror All KeyError exceptions for non-existent schema elements are ignored ignore_dit_content_rule A DIT content rule governing the structural object class is ignored >>> In some cases, though, the best source of documentation is the code itself. The last script in this article will provide an example of how the schema information can be used. An Example Script: suggest_attributes.py This example script compares the attributes in a user-specified record with the possible attributes, and prints out an annotated list of “suggested” available attributes. This script is longer than the other scripts in this article, but it makes use of similar techniques, and we will be able to move through it quickly.
Read more
  • 0
  • 0
  • 13109

article-image-front-page-customization-moodle
Packt
23 Oct 2009
11 min read
Save for later

Front Page Customization in Moodle

Packt
23 Oct 2009
11 min read
Look and Feel: An Overview Moodle can be fully customized in terms of layout and branding. It has to be stressed that certain aspects of changing the look and feel require some design skills. While you as an administrator will be able to make most of the relevant adjustments, it might be necessary to get a professional designer involved, especially when it comes to styling. The two relevant components for customization are the Moodle front page and Moodle themes, though this article will focus only on Moodle front page. Before going into further details, let's try to understand which part is responsible for which element of the look and feel of your site. Have a look at the screenshot that would follow. It shows the front page of Moodle site after you are logged in as an administrator. It is not obvious which parts are driven by the Moodle theme and by the front page settings. The next table sheds some light on this: Element Settings Theme Other Logos - x - Logged-in information (location and font) - x - Language Drop Down - - x Site Administration block (position) x - - Available Courses block (position) x - - Available Courses block (content) - - x Course categories and Calendar block (position) x - - Course categories and Calendar block (icons, fonts, colors) - x - Footer text - x - Footer logo - x - Copyright statement - x -   While this list is by no means complete, it hopefully gives you an idea that the look and feel of your Moodle site is driven by a number of different elemen In short, the settings (mostly front page settings as well as a few related parameters) dictate what content users will see before and after they log on. The theme is responsible for the design scheme or branding, that is, the header and footer as well as colors, fonts, icons, and so on used throughout the site. Now let's move towards the core part of this article. Customizing Your Front Page The appearance of Moodle's front page changes after a user has logged in. The content and layout of the page before and after login can be customized to represent the identity of your organization. Look at the following screenshot. It is the same site that the preceding screenshot was taken from, but before a user has logged in. In this particular example, a Login block is shown on the left and the Course categories are displayed in the center, as opposed to the list of available courses. Front Page Settings To customize the front page, you either have to be logged in as Moodle administrator, or have front-page-related permissions in the Front Page context. From the Site Administration block, select Front Page | Front Page Settings. The screen showing all available parameters will be loaded displaying your current settings that are changeable. ts. Setting Description Full site name This is the name that appears in the browser's title bar. It is usually the full name of your organization, or the name of the dedicated course, or qualification the site is used for. Short name for site This is the name that appears as the first item in the breadcrumb trail. Front Page Description This description of the site will be displayed on the front page via the Site Description block. It can, therefore, only be displayed in the left or right column, never in the center of the front page. The description text is also picked up by the Google search engine spider, if allowed. Front Page Moodle can display up to four elements in the center column of the front page when not logged in. List of courses List of categories News items Combo list(categories and courses) The order of the elements is the same as the one chosen in the pull-down menus. Front page items when logged in Same as "Front Page", but used when logged in. Include a topic section If ticked, an additional topic section (just like the topic blocks in the center column of a topics-format course) appears on top of the front page's center column. It can contain any mix of resources or activities available in Moodle. It is very often used to provide information about the site. News items to show Number of news items that are displayed. Courses per page This is a threshold setting that is used when displaying courses within categories. If there are more courses in a category than specified, page navigation will be displayed at the top of the page. Also, when a combo list is used, course names are only displayed if the number is less than the specified threshold. For all other categories, only the number of courses is shown after the category name. Allow visible courses within hidden categories By default, courses in hidden categories are not shown unless the said setting is applied. Default frontpage role If logged-in users should be allowed to participate in front page activities, a default front page role should be set. The default is None.   Arranging Front Page Blocks To configure the left and right column areas with blocks, you have to turn on editing (using the Blocks editing on button). The menu includes blocks that are not available in courses such as Course/Site description and Main menu. Blocks are added to the front page in exactly the same way as in courses. To change their position, use the standard arrows. The Main Menu block allows you to add any installed Moodle resource or activity inside the block. For example, using labels and links to (internal or external) websites, you are able to create a menu-like structure on your front page. If the Include a topic section parameter has been selected in the Front Page settings, you have to edit the part and add any installed Moodle activity or resource. This topic section is usually used by organizations to add a welcome message to visitors, often accompanied by a picture or other multimedia content. Login From a Different Website The purpose of the Login block is for users to authenticate themselves by entering their username and password. It is possible to log into Moodle from a different website, maybe your organization's homepage, effectively avoiding the Login block. To implement this, you will have to add some HTML code on that page as shown: <form class="loginform" name="login" method="post" action="http://www.mysite.com/login/index.php">   <p>Username :     <input size="10" name="username" />   </p>   <p>Password :     <input size="10" name="password" type="password" />   </p>   <p>     <input name="Submit" value="Login" type="submit" />   </p></form> The form will pass the username and password to your Moodle system. You will have to replace www.mysite.com with your URL. This address has to be entered in the Alternate Login URL field at Users | Authentication | Manage authentication in the Site Administration block. Other Front Page Items The Moodle front page is treated as a standalone component in Moodle, and therefore has a top-level menu with a number of features that can all be accessed via the Front Page item in the Site Administration menu. Having now looked in detail at the front page settings, let's turn to examining the other available options. Front Page Roles The front page has its own context in which roles can be assigned to users. This allows a separate user to develop and maintain the front page without having access to any other elements in Moodle. Since the front page is treated as a course, a Teacher role is usually sufficient for this. Front Page Backup and Restore The front page has its own backup and restore facilities to back up and restore all elements of the front page including any content. The mechanism of performing backup and restore is the same as for course backups.   Front page backups are stored in the backupdata folder in the Site Files area, and can be accessed by anybody who is aware of the URL. It is therefore best to move the created ZIP files to a more secure location. Front Page Questions Since the Moodle front page is treated in the same way as a course, it also has its own question bank, which is used to store any questions used on front-page quizzes. For more information on quizzes and the question bank, go to the MoodleDocs at http://docs.moodle.org/en/Quiz . Site Files The files areas of all courses are separate from each other, that is, files in Moodle belong to a course and can only be accessed by users who have been granted appropriate rights. The difference between Site files and the files area of any other course is that files in Site files can be accessed without logging in. Files placed in this location are meant for the front page, but can be accessed from anywhere in the system. In fact, if the location is known, files can be even be accessed from outside Moodle. Make sure that in the Site files area, you only place files that are acceptable to be seen by users who are not authenticated on your Moodle system. Typical files to be placed in this area are any images you want to show on the front page (such as the logo of your organization) or any document that you want to be accessed (for example, the curriculum). However, it is also used for other files that are required to be accessible without access to a course, such as the Site Policy Agreement, which has to be accepted before starting Moodle. To access these publicly available Site files elsewhere (for example, as a resource within other courses), you have to copy the link location that has the format: http://mysite.com/file.php/1/file.doc. Allow Personalization via My Moodle By default, the same front page is displayed for all users on your Moodle system. To relax this restriction and to allow users to personalize their own front page, you have to activate the My Moodle feature via the Force users to use My Moodle setting in Appearance | My Moodle in the Site Administration block. Once enabled, Moodle creates a /my directory for each user (except administrators) at their first login, which is displayed instead of the main Moodle front page. It is a very flexible feature that is similar to a customizable dashboard, but requires some more disk space on your server. Once logged in, users will have the ability to edit their page by adding blocks to their My Moodle area. The center of the page will be populated by the main front page, for instance displaying a list of courses, that users cannot modify. Making Blocks Sticky There might be some blocks that you wish to "stick", that is, display on each My Moodle page, making them effectively compulsory blocks. For example, you might want to pin the Calendar block on the top right corner of each user's My Moodle page. To do this, go to Modules | Blocks | Sticky blocks in the Site Administration block and select My Moodle from the pull-down menu. You can now add any item from the pull-down menu in the Blocks block. If the block is single instance (that is, only one occurrence is allowed per page), the block will not be available for the user to choose from. If the user has already selected a particular block, a duplicate will appear on their site, which can be edited and deleted. To prevent users from editing their My Moodle pages, change the moodle/my: manageblocks capability in the Authenticated user role from Allow to Not set. The sticky block feature is also available for course pages. A course creator has the ability to add and position blocks inside a course unless they have been made sticky. Select the Course page item from the same menu to configure the sticky blocks for courses, as shown in the preceding screenshot. Summary After providing a general overview of look and feel elements in Moodle, the article covered front page customization. As mentioned earlier, the front page in Moodle is a course. This has advantages (you can do everything you can do in a course and a little bit more), but it also has certain limitations (you can only do what you can do in a course and might feel limited by this). However, some organizations are now using the Moodle front page as their homepage.
Read more
  • 0
  • 0
  • 17368

article-image-securing-xml-documents
Packt
23 Oct 2009
11 min read
Save for later

Securing XML Documents

Packt
23 Oct 2009
11 min read
XML Security Threats All the components in web services are described in XML. SOAP and all the WS -Security specifications are XML formats. Hence it just makes sense for expressing security data in XML format. Fortunately, there has been no need to invent new cryptography technologies for XML. The XML security standards have used existing cryptography directly. XML-based data transfer has emerged as the standard for organizations to exchange business data. As with all communications over the public Internet, XML-based transfers have their own set of vulnerabilities to confront. Like any other document exchange, XML document exchange must support the usual security measures which are Confidentiality, Integrity, Authenticity, and Non-Repudiation. The following list illustrates some specific XML security threats: Schema Altering — Manipulation of WS schema to alter the data processed by the application.      XML Parameter Tampering — Injection of malicious scripts or content into XML parameters      Coercive Parsing — Injection of malicious content into the XML      Oversized Payload — Sending oversized files to create an XDoS attack      Recursive Payload — Sending mass amounts of nested data to create an XDoS attack against an XML parser      XML Routing Detours — Redirecting sensitive data within the XML path      External Entity Attack — An attack on an application that parses XML input from suspicious sources using an incorrectly configured XML parser These threats pose potentially serious problems to developers creating applications, components, and systems that depend on XML data. The solution for the above problems is XML Encryption. XML Encryption XML Encryption provides end-to-end security for applications that require secure exchange of structured data. XML itself is the most popular technology for structuring data, and therefore XML-based encryption is the natural way to handle complex requirements for security in data interchange applications. XML Encryption is a process for encrypting and decrypting parts of XML documents. Most of today's encryption schemes use transport-level techniques that encrypt an entire request and response stream between a sender and receiver, offering zero visibility into contents of the interchange to intermediaries. Contentlevel encryption converts document fragments into illegible ciphertext, while other elements remain legible as plaintext. Some features of XML encryption are: The ability to encrypt a complete XML file The ability to encrypt a single element of an XML file The ability to encrypt only the contents of an XML element The ability to encrypt binary data within an XML file Encrypting an XML File Here's a short sample XML file that can serve to demonstrate XML encryption:     <?xml version='1.0'?>    <POInfo >        <Name>FJ</Name>        <Amount>125.00</Amount>        <CreditCardNumber>1234-5678-4564-4321</CreditCardNumber>    <Date>July 6, 2006</Date>    </POInfo> When you encrypt an entire XML file, the process simply replaces the root element (<POInfo> in the sample) with an <EncryptedData> element that contains the encryption details, including the encrypted content. Here is how the encrypted file will look:     <?xml version="1.0" encoding="UTF-8"?>    <xenc:EncryptedData                Type="http://www.w3.org/2001/04/xmlenc#Element">        <xenc:EncryptionMethod            Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"            />        <ds:KeyInfo >            <xenc:EncryptedKey                >                <xenc:EncryptionMethod                    Algorithm="http://www.w3.org/2001/04/xmlenc#kw-tripledes"                    />                <xenc:CipherData                    >                    <xenc:CipherValue                        >                        MKeT0ZmHFLwnZaSXO+oZSxlSJ5/BqvblqG76B3nOMU0=                    </xenc:CipherValue>                </xenc:CipherData>            </xenc:EncryptedKey>        </ds:KeyInfo>        <xenc:CipherData            >            <xenc:CipherValue                >                    +M/Tamk/62Lut4HqLpU/es9sdhnNTTpasbeszN8GN8EAJZsX0vvClcKEW                    UAgIdbvyJpprQ+jUIiWJKTz1X3L6VAefHqO963pU3bzmGMo                    pHLqS1Eg7iAPFhKV1PJclyswyyepEjyu+bOgqzgGnS1XA0/V                    NP7kLK70rB2Zb0DSbaCi+7HjTNGWF9YKtPIP5bvrs5xw+x                    HnKO++2EuqzK+deD7mCu8w6sG9vmRCrUR99Mx1QDZon9a2962ZD                    FSwoIJKg5I83GzOU+RObBBUme+yTf7UWybEiwtHp5ZgvuaQYJA=            </xenc:CipherValue>        </xenc:CipherData>    </xenc:EncryptedData> Encrypting a Single Element To encrypt a single element of an XML file, you specify the desired child element, rather than the root element of the input file as the element to encrypt. The following snippet shows the results of encrypting only the <CreditCardNumber> element of the sample file.     <?xml version="1.0" encoding="UTF-8"?>    <POInfo >        <Name>John Doe</Name>        <Amount>125.00</Amount>        <xenc:EncryptedData                        Type="http://www.w3.org/2001/04/xmlenc#Element">            <xenc:EncryptionMethod                Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"                />            <ds:KeyInfo >                <xenc:EncryptedKey                    >                    <xenc:EncryptionMethod                        Algorithm=                            "http://www.w3.org/2001/04/xmlenc#kw-tripledes"                        />                    <xenc:CipherData                        >                        <xenc:CipherValue                            >                                6zhAcEW7KIKrbSjEOkXDrVkmws5zhQQLDO4YYW+RfRY=                        </xenc:CipherValue>                    </xenc:CipherData>                </xenc:EncryptedKey>            </ds:KeyInfo>            <xenc:CipherData                >                <xenc:CipherValue                    >                    JqsRmdSoS+PXqCe80Y8zNiQ49sHTLNaAgHX1Ja7d+u9fv                    TFBrkBMK7C7EHsQTglZ3yT9yCZDuFnjBoQTLULKqOy71Qw                    EPRPObtYLPIJgy1vUdNrw47uDmJ/R5r/B0SH37HN8mfNv                    i50zPt1qPxxRwA==                </xenc:CipherValue>            </xenc:CipherData>        </xenc:EncryptedData>        <Date>July 6, 2005</Date>    </POInfo> Notice that the encryption process replaced the <CreditCardNumber> tag and its contents with an <EncryptedData> tag, while leaving the siblings of the <CreditCardNumber> element unaltered. This type of encryption can be performed using XML Signature and Encryption. The interested reader may look up the implementation at the Apache site (http://xml.apache.org/security/). Best practices for XML encryption, can be summarized as follows: It is good to have standard element tags for representing encrypted elements within the XML documents. This will enable parsers to better understand encrypted elements and data during the validation process.      It is necessary to provide means for encrypting only the desired elements within an XML document instead of encrypting the whole document. This will pave the way for incorporating several confidential data elements that are intended for different recipients within a single XML document.      There should be standard mechanisms for exchanging the secret keys used for encryption and decryption processes.      The standard should allow encryption of different parts of the document with different keys, so that multiple recipients can decrypt only those portions that are intended for them.      The standards should be adaptable to both ASCII and binary data.      The standards should be adaptable to different cryptographic algorithms.      The standards should work along with other XML security standards and specifications.
Read more
  • 0
  • 0
  • 5295
article-image-comparing-cursor-and-set-approaches-processing-relational-data
Packt
23 Oct 2009
5 min read
Save for later

Comparing Cursor and Set Approaches in Processing Relational Data

Packt
23 Oct 2009
5 min read
To give you an idea about cursor, the following DECLARE statement creates a cursor (named zero_bal_crs), which gives you access to the rows of a payment table, rows that have 100 or less balances. DECLARE zero_bal_crs CURSOR FOR SELECT * FROM payment WHERE payment_bal < 100 You then fetch and process each of the rows sequentially; the process can be, for example, summing up rows by product group and loading the sums into a summary table. You develop the process outside of the cursor, for example, in a stored procedure. (You’ll see in the examples that the cursor-based process is procedural). Instead of processing row-by-row sequentially, you can process relational data set-by-set, without a cursor. For example, to sum all payment rows with 100 or less balances and load it into a table (named payment_100orless_bal in the following SQL statement), you can use the following SQL statement. This single SQL statement completely processes the rows that meet the condition, all at once, as a set. INSERT INTO payment_100orless_bal SELECT SUM(payment_bal) FROM payment WHERE payment_bal < 100 The following three examples, which are among those I most frequently encountered, further compare cursor-based processing with set processing. Example 1: Sequential Loop cf. One SQL Statement Our process in the first example is to summarize sales transactions by product. Listing 1 shows the DDLs for creating the sales transaction table and sales product table that stores the summary. Listing 1.1: DDLs of the Example 1 Tables CREATE TABLE sales_transactions( product_code INT, sales_amount DEC(8,2), discount INT);CREATE TABLE sales_product(product_code INT, sales_amount DEC(8,2)); Listing 1.2 shows a cursor-based stored procedure that implements the process. In this example, what the cursor (sales_crs) does is simply putting all rows in ascending order by their product codes. As you might have expected, this stored procedure applies loop with if-then-else programming construct to process the data row-by-row. Listing 1.2 Cursor Procedural solution DELIMITER $$DROP PROCEDURE IF EXISTS ex1_cursor $$USE sales $$CREATE PROCEDURE ex1_cursor()BEGINDECLARE p INT DEFAULT 0;DECLARE s DECIMAL(8,2) DEFAULT 0;DECLARE d INT DEFAULT 0;DECLARE done INT DEFAULT 0;DECLARE first_row INT DEFAULT 0;DECLARE px INT DEFAULT 0;DECLARE sx DECIMAL(8,2) DEFAULT 0;DECLARE sales_crs CURSOR FOR SELECT * FROM sales_transactions ORDER BY product_code;DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;OPEN sales_crs; REPEAT FETCH sales_crs INTO p, s, d;IF first_row = 0 THEN SET first_row = 1; SET px = p; SET sx = s * (100 - d)/100; ELSEIF NOT done THEN IF p <> px THEN INSERT INTO sales_product VALUES(px, sx); SET sx = s * (100 - d)/100; SET px = p; ELSE SET sx = sx + s * (100 - d)/100; END IF; ELSE INSERT INTO sales_product VALUES(px, sx); END IF; UNTIL done END REPEAT;CLOSE sales_crs;END $$DELIMITER ; The stored procedure in Listing 1.3 implements a set, processing to accomplish the same purpose as its foregoing cursor-based processing. You can see that this stored procedure is simpler than its cursor-based counterpart. Listing 1.3 Set Operation solution DELIMITER //USE sales //DROP PROCEDURE IF EXISTS ex1_sql //CREATE PROCEDURE ex1_sql ()BEGIN INSERT INTO sales_product SELECT product_code , SUM(sales_amount * (100 - discount)/100) FROM sales_transactions GROUP BY product_code;END //DELIMITER ; Example 2: Nested Cursor cf. Join Our 2nd example is to consolidate order by customer. While example 1 has one table, example 2 has two: order and item. The DDLs of the two tables are shown in Listing 2. To process two tables, our cursor implementation uses a nested loop (Listing 2.2) which makes it even more complex than example 1. Listing 2.1: DDL’s of the Example 2 Tables CREATE TABLE order ( , order_number INT , order_date DATE , customer_number INT);CREATE TABLE item ( , order_number INT , product_code INT , quantity INT , unit_price DEC(8,2)); Listing 2.2: Nested Cursor DELIMITER $$DROP PROCEDURE IF EXISTS ex2_cursor $$CREATE PROCEDURE ex2_cursor()BEGINDECLARE so INT;DECLARE sc INT;DECLARE io INT;DECLARE iq INT;DECLARE iu DEC(10,2);DECLARE done1 VARCHAR(5) DEFAULT 'START' ;DECLARE done2 VARCHAR(5) DEFAULT 'START' ;DECLARE sales_crs CURSOR FOR SELECT customer_number, order_number FROM sales_order ORDER BY customer_number, order_number;DECLARE order_crs CURSOR FOR SELECT order_number, quantity, unit_price FROM item WHERE order_number = so ORDER BY order_number;DECLARE CONTINUE HANDLER FOR NOT FOUND SET done1 = 'END';OPEN sales_crs; WHILE done1 <> 'END' DO FETCH sales_crs INTO sc, so; IF done1 <> 'END' THEN/* inner cursor */ OPEN oorder_crs; SET done2 = done1; WHILE done1 <> 'END' DO FETCH order_crs INTO io, iq, iu; IF done1 <> 'END' THEN INSERT INTO customer_order VALUES (sc, iq * iu); END IF;END WHILE; CLOSE order_crs; SET done1 = done2; END IF; END WHILE;CLOSE sales_crs;END $$DELIMITER ; Listing 2.3 is the set solution. We apply join in this 2nd example which makes it just a single SQL statement. You can see that this set stored procedure is again simpler than its cursor-based equivalent.    
Read more
  • 0
  • 0
  • 5580

article-image-layouts-ext-js
Packt
23 Oct 2009
9 min read
Save for later

Layouts in Ext JS

Packt
23 Oct 2009
9 min read
What are layouts, regions, and viewports? Ext uses Panels, which are the basis of most layouts. We have used some of these, such as FormPanel and GridPanel, already. A viewport is a special panel-like component that encloses the entire layout, fitting it into the whole visible area of our browser. For our first example, we are going to use a viewport with a border layout that will encapsulate many panels. A viewport has regions that are laid out in the same way as a compass, with North,South, East and West regions—the Center region represents what's left over in the middle. These directions tell the panels where to align themselves within the viewport and, if you use them, where the resizable borders are to be placed: The example we're creating will look like the following image, and combines many of the previous examples we have created: This layout is what's called a 'border' layout, which means that each region is separated by a somewhat three dimensional border bar that can be dragged to resize the regions. This example contains four panel regions: North: The toolbar West: A form Center: Grid in a tab panel East: A plain panel containing text Note that there is no 'South' panel in this example—not every region needs to be used in every layout. Our first layout Before we create our layout that uses only four regions let's go ahead and create a layout that utilizes all the regions, and then remove the South panel. We are going to create all of the regions as 'panels', which can be thought of as blank canvases to which we will add text, HTML, images, or even Ext JS widgets. var viewport = new Ext.Viewport({ layout: 'border', renderTo: Ext.getBody(), items: [{ region: 'north', xtype: 'panel', html: 'North' },{ region: 'west', xtype: 'panel', split: true, width: 200, html: 'West' },{ region: 'center', xtype: 'panel', html: 'Center' },{ region: 'east', xtype: 'panel', split: true, width: 200, html: 'East' },{ region: 'south', xtype: 'panel', html: 'South' }]}); Each region is defined as one of the four compass directions—East, West, North, and South. The remainder in the middle is called the center region, which will expand to fill all of the remaining space. Just to take up some blank space in each region and to give a visual indicator as to where the panels are, we defined an 'HTML' config that has just text. (This could also contain complex HTML if needed, but there are better ways to set the contents of panels which we will learn about soon). Ext JS provides an easy, cross-browser compatible, speedy way to get a reference to the body element, by using Ext.getBody(). If everything works out ok, you should see a browser that looks like this: Now we have a layout with all five regions defined. These regions can have other text widgets added into them, seamlessly, by using the xtype config. Alternatively they can be divided up separately into more nested regions—for instance, the center could be split horizontally to have its own South section. A 'Center' region must always be defined. If one is not defined, the layout will produce errors and appear as a jumbled set of boxes in the browser. Splitting the regions The dividers are set up for each panel by setting the split flag—the positioning of the dividers is determined automatically based on the region the panel is in. split: true For this page, we have set the West and East regions as 'split' regions. This, by default, makes the border into a resizing element for the user to change the size of that panel. I want options Typically, when a split is used, it's combined with a few other options that make the section more useful, such as width, minSize, and collapseMode. Here are some of the more commonly-used options: Option Value Description split true/false Boolean value that places a resizable bar between the sections collapsible true/false Boolean value that adds a button to the title bar which lets the user collapse the region with a single click collapseMode Only option is mini mode, or undefined for normal mode When set to 'mini', this adds a smaller collapse button that's located on the divider bar, in addition to the larger collapse button on title bar; the panel also collapses into a smaller space title String Title string placed in the title bar bodyStyle CSS CSS styles applied to the body element of the panel. minSize Pixels, ie: 200 The smallest size that the user can drag this panel to maxSize Pixels, ie: 250 The largest size that the user can drag this panel to margins In pixels: top, right, bottom, left, i.e.,: 3 0 3 3 Can be used to space the panel away from the edges or away from other panels; spacing is applied outside of the body of the panel cmargins In pixels: top, right, bottom, left, i.e.,: 3 0 3 3 Same idea as margins, but applies only when the panel is collapsed   Let's add a couple of these options to our west panel: { region: 'west', xtype: 'panel', split: true, collapsible: true, collapseMode: 'mini', title: 'Some Info', bodyStyle:'padding:5px;', width: 200, minSize: 200, html: 'West'} Adding these config options to our west panel would give us the following look: Expanding and collapsing a panel that does not have a width specified can produce rendering problems. Therefore, it's best to specify a width for panels—of course this is not needed for the center, as this panel automatically fills the remaining space. Tab panels With Ext JS, tab panels are also referred to as a "card" layout because they work much like a deck of cards where each card is layered directly above or below the others and can be moved to the top of the deck, to be visible. We also get pretty much the same functionality in our tab panel as a regular panel, including a title, toolbars, and all the other usual suspects (excluding tools). Adding a tab panel If the Ext JS component is a panel type component, for instance GridPanel andFormPanel, then we can add it directly to the layout using its xtype. Let's start by creating a tabPanel: { region: 'center', xtype: 'tabpanel', items: [{ title: 'Movie Grid', html: 'Center' }]} The items config is an array of objects that defines each of the tabs contained in this tabpanel. The title is the only option that's actually needed to give us a tab, and right now html is just being used as a placeholder, to give our empty tab some content. We will also need to add an activeTab config that is set to zero to our tab panel. This is the index of the tabs in the panel left to right starting with zero and counting up for each tab. This tells the tab panel at position zero to make itself active by default, otherwise, we would have no tabs displayed, resulting in a blank section until the user clicked a tab. { region: 'center', xtype: 'tabpanel', activeTab: 0, items: [{ title: 'Movie Grid', html: 'Center' }]} If we take a look at this in a browser, we should see a tab panel in the center section of our layout. Adding more tabs is as easy as adding more items into the items array. Each tab item is basically its own panel, which is shown or hidden, based on the tab title that has been clicked on the tab panel. { region: 'center', xtype: 'tabpanel', activeTab: 0, items: [{ title: 'Movie Grid', html: 'Center' },{ title: 'Movie Descriptions', html: 'Movie Info' }]} Both the Movie Grid and Movie Descriptions tabs are just plain panels right now. So let's add some more configuration options and widgets to them. Widgets everywhere Earlier, I mentioned that any type of panel widget could be added directly to a layout, just as we had done with the tabs. Let's explore this by adding another widget to our layout—the grid. Adding a grid into the tabpanel As we now have these tabs as part of our layout, let's start by adding a grid panel to one of the tabs. Adding the xtype config option to the grid config code will produce a grid that fills one entire tab: { region: 'center', xtype: 'tabpanel', activeTab: 0, items: [{ title: 'Movie Grid', xtype: 'gridpanel', store: store, autoExpandColumn: 'title', columns: // add column model //, view: // add grid view spec // },{ title: 'Movie Descriptions', html: 'Movie Info' }]} xtypes offer a quick way to instantiate a new component with minimal typing. This is sometimes referred to as 'lazy rendering' because the components sit around waiting to be displayed before they actually execute any code. This method can help conserve memory in your web application. As we are adding this grid to a tab—which is essentially just a panel—there are some things that we no longer need (like the renderTo option, width, height, and a frame).The size, title, and border for the grid are now handled by our tab panel. Now we should have a layout that looks like this: Accordions The accordion is a very useful layout that works somewhat like a tab panel, where we have multiple sections occupying the same space, with only one showing at a time. This type of layout is commonly used when we're lacking the horizontal space needed for a tab panel, but instead have more vertical space available. When one of the accordion panels is expanded, the others will collapse. Expanding and collapsing the panels can be done either by clicking the panel's title bar or by clicking the plus/minus icons along the rightmost side of the panel.    
Read more
  • 0
  • 0
  • 4840
Modal Close icon
Modal Close icon