Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Web Development

1802 Articles
article-image-drupal-theming
Packt
14 Sep 2010
9 min read
Save for later

Drupal Theming

Packt
14 Sep 2010
9 min read
(For more resources on Drupal, see here.) 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 mask for your site that can be modified in order to achieve virtually any design criteria. Of course, different themes have widely 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. It is also important to understand that not all downloadable themes are of the same quality. Some are designed better than others. This article utilizes Zen, which is one of the cleanest and most flexible around. Different themes are implemented differently. Some themes use fixed layouts with tables (avoid these because web design should not rely on tables), while others use div tags and CSS (favor these as they are far more flexible and powerful)—you should play around with a variety of themes in order to familiarize yourself with a few different ways of creating a web page. As mentioned, we only have space to cover Zen here, but the lessons learned are easily transferred to other themes 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 Drupal themes consist of a set of files that define and control 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. Different Drupal 7 template files control different regions of a page, as shown in the following diagram: 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. However, 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 PHP Template 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 on 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—that is, not block, box, comment, node, or page. The themes folder also houses the stylesheets along with images, and in the case of the default theme, colors. Of special interest is the .info file that contains information about the theme to allow Drupal to find and set a host of different parameters. A theme's .info file holds the basic information about a theme that Drupal needs to know, namely, its name, description, features, template regions, CSS files, and JavaScript. Here's Garland's .info file: ; $Id: garland.info,v 1.9 2009/12/01 15:57:40 webchick Exp $name = Garlanddescription = A multi-column theme which can be configured to modifycolors and switch between fixed and fluid width layouts.package = Coreversion = VERSIONcore = 7.xengine = phptemplatestylesheets[all][] = style.cssstylesheets[print][] = print.csssettings[garland_width] = fluid; Information added by drupal.org packaging script on 2010-05-23version = "7.0-alpha5"project = "drupal"datestamp = "1274628610" Note that this file holds, amongst other things: Name—A human-readable theme name Description—A description of the theme Core—The major version of Drupal that the theme is compatible with Stylesheets—Stipulate which stylesheets are to be used by the theme These are not the only types of information that can be held by .info files. As we'll see a bit later on, when it's time to add scripts to a theme, they can be added to the .info file too. To quickly see one way in which .info files can be put to work, look closely at the .info file in the update_test_subtheme theme folder in tests (Below garland): ; $Id: update_test_subtheme.info,v 1.1 2009/10/08 15:40:34 dries Exp $name = Update test subthemedescription = Test theme which uses update_test_basetheme as the basetheme.core = 7.xengine = phptemplatebase theme = update_test_basethemehidden = TRUE; Information added by drupal.org packaging script on 2010-05-23version = "7.0-alpha5"project = "drupal"datestamp = "1274628610" Notice that this contains a base theme directive that is used to specify the parent, or base, theme. 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 themes directory and specifying the base theme directive in the new theme's .info file—just as we saw in update_test_subtheme. 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 stylesheets 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. I should make it 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 | all folder, and add your new theme folder in there—call it whatever you want (provided it is a unique name) 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) Rewrite the .info file to reflect the attributes and requirements of the new theme, including specifying the base theme directive Modify the layout (this is where your PHP and HTML skills come in handy) and add some flavor with your own stylesheet (included into the new theme through the .info file) Before moving on, there's one small issue of practicality that must be addressed. 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 a developer toolbar and view the formatted sources' extensions. I wholeheartedly agree. You can obtain a copy of the Firefox browser at www.mozilla.com/firefox. Firefox should also be extended with Firebug, which is an extremely useful tool for client-side web debugging: https://addons.mozilla.org/en-US/firefox/addon/1843/. Choosing a base theme As discussed, Drupal ships with a few default themes, and there are quite a few more available in the Downloads section of the Drupal site. Looking at how Drupal presents its core Themes page under Appearance in the toolbar menu, we can see the following: Any new themes that are added to the site will be used to enable, disable, configure, or set as a default from this page. Be aware that some themes might not implement functionality that is important to your site. Ensure that you test each theme thoroughly before allowing users to select it. Enabling the Stark theme, and setting it as the default theme, causes the site, which has been presented in the standard Garland theme up until now, to look something like this: This is a vast change from the previous look. Notice too that the entire layout of the site has changed—there are no well defined columns, no visually defined header section, and so on. In addition, the previous fonts and colors have also been demolished. Take the time to view each theme that is available by default in order to get a feel for how different themes can produce wildly differing looks and layouts. That is not the end of the story, because the Drupal site also has a whole bunch of themes for us to explore. So head on over to the themes page at http://drupal.org/project/themes and select the relevant version tab to bring up the themes that are available. You have already seen how to download and install other modules, and the process for installing themes is no different—download and extract the contents of the desired theme to the themes folder in sites | default or sites | all. For example, the Zen theme was downloaded and extracted, and provides us with a new option in the list of themes (some downloads will provide a number of sub-themes too), as shown in the following screenshot: Enable and set default causes the site to look like the next screenshot: Notice that while the color scheme is effectively non-existent, the page has retained its overall structure in that it has defined sidebars, a header region, and a central content region. Before we begin customizing this, let's take a look at the configuration settings for this theme.
Read more
  • 0
  • 0
  • 2335

article-image-creating-and-styling-container-images-using-dotnetnuke
Packt
08 Sep 2010
4 min read
Save for later

Creating and Styling Container Images using DotNetNuke

Packt
08 Sep 2010
4 min read
Creating custom container images Containers can do more than just act as placeholders for module content. By expanding the container skin to include images we can create more elaborate containers limited only by our creativity. Styling a DNN container using images is a two-part process. First we must create the images we need and save them as a set of graphic files. Then we must design the container to position the images around the container. In this recipe we will see how to create the custom images for styling a container. In the next recipe Styling a container with images we'll see how to position these images to create the final container. Getting ready Here is a diagram that shows what the final container will look like. We need to create the five images highlighted in red. As you can see in this diagram, we need only create images for the distinctive elements. CSS can fill in the gaps by repeating the background image as necessary to fit the size of the container. Creating images for a container is a four-step process: Decide which sides of the container will use images. In this example we will create images for the top and bottom container edges and leave the left and right sides as a simple border line. Decide the size of the images. A container border can be very narrow or very wide. In this example we will create a 27 pixel wide border with the images. Decide which images will tile to support variable-sized containers. As containers can stretch or shrink, we need to use an image that can tile. That is, the image can be repeated as many times as necessary to fill the width of the container. In this example, we will pick one image to tile across the top and another to tile along the bottom. As the sides will be just a border line we won't need to worry about tiling vertically. Choose a drawing application (such as MS Paint) to create the images and save them to a temporary folder. You can use a variety of formats—in this example we will save the images as GIF files to save space. How to do it... Start by launching your favorite drawing application (such as MS Paint). Set the image dimensions to 98 pixels wide and 27 pixels high. There's nothing special about these dimensions, they just look good for this particular design. Draw the image for the upper-left corner of the container. This image will be the background for the title of the module, so it needs to be an image that can tile horizontally as the length of a container title varies. Save the image as a GIF file called ContainerUL.gif. Next, create a new image with dimensions 80 by 27 pixels. This image marks the end of the module title and the beginning of the top container border. It does not tile and is used in this example to connect the upper-left corner to the border image that runs across the top of the container. Save the image as a GIF file called ContainerUC1.gif. The next image is the top border of the container and will tile horizontally as the width of the container changes. Set the attributes to be 12 by 27 pixels. Save the image as a GIF file called ContainerUC2.gif. For the border along the bottom of the container, we need two more images. The first is the lower-left corner. Make this image 90 by 27. This image will tile across the bottom for the width of the container. Save the image as a GIF file called ContainerLL.gif. The last image is for the lower-right corner. This image doesn't tile. Make it 100 by 27 pixels. 12. Save the image as a GIF file called ContainerLR.gif. At this point you should have five images in a temporary folder that look something like this: (Move the mouse over the image to enlarge.) There's more... In this recipe we saw how to create images for a container and a little bit on how the images can form the borders of a container. In the next recipe we will see how to create the container that will use these images.
Read more
  • 0
  • 0
  • 2918

article-image-deploying-and-exploring-skin-objects-using-dotnetnuke
Packt
08 Sep 2010
7 min read
Save for later

Deploying and Exploring Skin Objects using DotNetNuke

Packt
08 Sep 2010
7 min read
Deploying your skins and containers Like a module, skins must be packaged and deployed to your DNN server. Once deployed, they will appear on the Skins page under the Admin menu for preview and applying to the portal. In previous article, we saw how to create new skins directly on a test DNN portal. This allows you to edit the files and immediately see the results just by refreshing your browser. But once a skin has been fully developed, this recipe will show you how to package your skin into a portable ZIP file using the package wizard. Once created, you can install the skin package on the DNN site by logging in as SuperUser then uploading the ZIP file and installing the skin package as an extension. The skin is installed in the Portals_defaultSkins folder. As of DNN 5.x, only the SuperUser can deploy skins. This was done as a security precaution as skins can now contain user-written code. Getting ready For this recipe you will need skin files to deploy. We will use the skin files from the previous article, from the recipe: Creating a simple ASCX skin. How to do it... Begin by logging in as the SuperUser. Look under the Host menu and select Extensions. The first step is to look under the installed extensions and find the SampleASCXSkin under the Skins section. If you see it, skip to step 8, otherwise you must create the extension first. Start by selecting Create Extension from the action menu (or click on the link at the bottom of the page). Choose Skin from Extension Type drop down and fill out the form as shown: (Move the mouse over the image to enlarge.) Click on Next. Provide the owner information and click on Next. The SampleASCXSkin skin will now appear in the list of extensions. Click on the Edit icon next to the name. Scroll to the bottom and click on the link Create Package. The Create Package screen will display. Click on Next. On the next screen you will see the files of the skin. Click on Next. Next, the manifest is displayed. Click on Next. The wizard will now generate a file name for the ZIP file using the owner name and the skin name. Click on Next. The wizard will now complete with a summary page. You will now find a ZIP file in the /Install/Skin folder. Click on Return to close the wizard. Once the file is packaged in a ZIP file you can upload and install it. Exploring Skin Objects In this recipe we will expand the sample ASCX skin and demonstrate additional Skin Objects you can use. Getting ready To follow along with this recipe you must have completed the following recipe: Creating a simple ASCX skin Here is a diagram of the new page layout we will create: How to do it... Start by locating the default skin folder within your test DNN portal (Portals_defaultSkins). Next, create a new folder to hold the skin files. Call this folder DetailedASCXSkin. Launch the Development Tool. Open the SampleASCXSkin.ascx file from the Creating a simple ASCX skin recipe. Add the following register directive after the existing directives: <%@ Register TagPrefix="dnn" TagName="BREADCRUMB" Src="~/Admin/Skins/BreadCrumb.ascx" %> <%@ Register TagPrefix="dnn" TagName="TEXT" Src="~/Admin/Skins/Text.ascx" %> <%@ Register TagPrefix="dnn" TagName="LINKS" Src="~/Admin/Skins/Links.ascx" %> <%@ Register TagPrefix="dnn" TagName="COPYRIGHT" Src="~/Admin/Skins/Copyright.ascx" %> <%@ Register TagPrefix="dnn" TagName="CURRENTDATE" Src="~/Admin/Skins/CurrentDate.ascx" %> Next, replace the existing Login_Style DIV with a new DIV encompassing both Login and User links: <%--By placing the SkinObjects inside a parent DIV they share the same style--%> <div class="bread_bg"> <div id="bread_style"> <dnn:TEXT runat="server" id="dnnTEXT" CssClass="breadcrumb_text" Text="You are here" ResourceKey="Breadcrumb" /> &nbsp;<span> <dnn:BREADCRUMB runat="server" id="dnnBREADCRUMB" CssClass="Breadcrumb" RootLevel="0" Separator="&nbsp;>&nbsp;" /> </span> </div> <div id="login_style" class="user"> <dnn:USER runat="server" id="dnnUSER" CssClass="user" /> &nbsp;&nbsp;|&nbsp;&nbsp; <dnn:LOGIN runat="server" id="dnnLOGIN" CssClass="user" /> </div> </div> Lastly, leave the ContentPane DIV as it is and add these new DIVs right below it: <div class="bot_bg links"> <dnn:LINKS runat="server" id="dnnLINKS" CssClass="links" Level="Root" Separator="&nbsp;&nbsp;&nbsp;| &nbsp;&nbsp;&nbsp;" /> </div> <div class="bot_pad"> <div id="copy_style" class="footer"> <dnn:COPYRIGHT runat="server" id="dnnCOPYRIGHT" Align CssClass="footer" /> </div> <div id="date_style" class="footer"> <dnn:CURRENTDATE runat="server" id="dnnCURRENTDATE" Align CssClass="footer" /> </div> </div> Separating the Copyright and Date into separate DIVs allow us to put one in the lower-left corner and one in the lower-right corner of the page. Select Save SampleASCXSkin.ascx As… from the File menu. Browse to the DetailedASCXSkin folder and save the file as DetailedASCXSkin.ascx. These new Skin Objects will need styles. Open the skin.css file from the Creating a simple ASCX skin recipe. Add the following styles to the bottom of the skin.css file: /*breadcrumbs*/ .Breadcrumb, a.Breadcrumb:link, a.Breadcrumb:active, a.Breadcrumb:visited {color: #800000; font-size: 13px;} a.Breadcrumb:hover {color: #C00;} .bread_bg {background-color: #EAEAEA; fontfamily: Verdana, Arial, Helvetica, sans-serif; border-left: solid 1px #EAEAEA; border-right: solid 1px #EAEAEA; margin: 0 5px 0 5px; height: 30px;} #bread_style {float: left; padding: 10px 0px 0px 17px; color: #000000; font-size: 13px;} /* for the bottom of the page */ .bot_bg {background-color: #EAEAEA; border-left: solid 1px #EAEAEA;border-right: solid 1px #EAEAEA; border-bottom: solid 1px #EAEAEA; padding: 10px; margin: 0 5px 0 5px;} .bot_pad {font-family: Verdana, Arial, Helvetica, sans-serif; margin-bottom: 20px; padding: 0 30px 0 20px;} #terms_style {float: left;} #copy_style {float: left;} #date_style {float: right; padding: 0px 0px 0px 10px; } /*links*/ .links {text-align: center;} .links, a.links:link, a.links:active, a.links:visited {fontweight: bold; color: #800000; font-size: 11px;} a.links:hover {color: #C00;} /* Sets the font size and text color of the footer at the bottom of the page */ .footer, a.footer:link, a.footer:active, a.footer:visited {color: #800000; font-size: 12px;} a.footer:hover {color: #C00;} With these styles we are positioning the Breadcrumb links just below the menu on the left. The Login and User links remain on the right side, ContentPane and RightPane stay the same, and the new Links, Copyright, and CurrentDate controls are arranged along the bottom of the page. Select Save skin.css As… from the File menu. Browse to the DetailedASCXSkin folder and save the file as skin.css. To see how the new skin will look on the site, log in as the SuperUser. Look under the Admin menu and select Skins. The new DetailedASCXSkin will now appear: Click on Preview to see how the skin looks: See how the breadcrumbs (You are here:) appear on the left under the menu, user and login are on the right, and links along the bottom and the copyright message and current date appear in the bottom corners. There's more... If you're curious to see which Skin Objects are available on your DNN site, you can log in as the SuperUser and select Extensions under the Host menu. This will list all the skin objects and their version number. Some skin objects may not be installed by default and will not appear in this list until installed.
Read more
  • 0
  • 0
  • 1746

article-image-creating-simple-skin-using-dotnetnuke
Packt
08 Sep 2010
5 min read
Save for later

Creating a Simple Skin using DotNetNuke

Packt
08 Sep 2010
5 min read
Introduction In DNN, skinning is a term that refers to the process of customizing the look and feel of the DNN portal. One of the powerful features of DNN is that the functionality of the portal is separated from the presentation of the portal. This means we can change the appearance of the portal without affecting how the portal works. To create a skin in DNN we will work with three kinds of files: HTML, ASCX, and CSS. The HTML or ASCX file describes the layout of the page and the CSS file provides the styling. If you have worked with HTML and CSS before than you will be able to immediately get started. However, if you are familiar with ASCX (and as a DNN developer that is likely) you can achieve the same results faster than HTML. In the recipes, we will show primarily ASCX skinning with some brief examples of HTML skinning. Skin Objects Before we start looking at the recipes, we need a quick word about Skin Objects. Skin Objects are used in both HTML and ASCX skin files as placeholders for different kinds of dynamic functionality. In HTML skins, you place text tokens such as [CURRENTDATE] in your code and when the code is parsed by the skin engine it will insert the matching skin object. If you are working in ASCX, you register skin objects as controls that you place directly in your code. DNN offers many different skin objects such as CurrentDate, Logo, Login link, and others and we'll see many of these in action in the recipes of this article. Downloading and installing a skin Often the easiest way to start skinning is to download an existing skin package and see the different files used for skinning. In this recipe we will download an excellent skin created by Jon Henning from a site called CodePlex that demonstrates the most common skin objects and layouts. Another reason for starting with an existing skin is that it allows incremental development. We can start with a fully functional skin, deploy it to our DNN portal and then edit the source files right on the server. In this way the changes we make are immediately displayed and problems are easily spotted and fixed. However, as applying a skin can affect the entire site, it is best to create and test skins on a development DNN site before using them on a production site. Finally, it should also be noted that as a skin is really just another type of extension in DNN, you are already familiar with some of these steps. How to do it... Open your favorite web browser and go to the site http://codeendeavortemplate.codeplex.com/. Click on Downloads in the toolbar. Scroll down a little and click on the CodeEndeavors Template Skin link. When prompted with the License Agreement, click I Agree. The File download dialog will ask if you want to Open or Save. Click on Save and select a temporary folder to hold the ZIP file. That's all we need from the CodePlex site, so close the browser. To install the skin on the DNN site, begin by logging in as the SuperUser. Look at the Control Panel and make sure you're in Edit mode. Look under the Host menu and select Extensions. Scroll to the bottom and click on the link Install Extension Wizard. The wizard will prompt for the ZIP file (called the extension package). Click on the Browse button and select the file you just downloaded (for example CodeEndeavors.TemplateSkin.install.v01.01.07.00.zip). Click on Open then click on Next. The wizard will display the Extension information. Click on Next. The wizard will display the Release Notes. Click on Next. On the license page, check Accept License? and click on Next. Now the install script will run, creating the skin. At the end you should see the message "Installation successful". Click on Return. To make the skin active, select Skins under the Admin menu. (Move the mouse over the image to enlarge.) From the Skins drop-down lists, select CodeEndeavors.TemplateSkin. For this article, we will use the Index skin for our examples. Click on the Apply link under the index skin to make it active. To see the skin files, you can look in the root folder of the DNN instance under Portals_defaultSkinsCodeEndeavors.TemplateSkin. Here is a summary of the key files you are likely to see in a skin like this: File name Description animated.ascx An ASCX skin file. container.ascx An ASCX container file. index.html An HTML skin file. skin.css The stylesheet for the skin. container.css The stylesheet for the container. TemplateSkin.dnn The manifest file for the skin package. thumbnail_animated.jpg A preview image of the ASCX skin. thumbnail_container.jpg A preview image of the ASCX container. thumbnail_index.jpg A preview image of the HTML skin. license.txt The text of the license agreement. releasenotes.txt The text of the release notes. version.txt The version number. Images folder A folder holding the graphic images supporting a skin or container.
Read more
  • 0
  • 0
  • 3143

article-image-drupal-site-configuration-site-information-triggers-and-file-system
Packt
08 Sep 2010
9 min read
Save for later

Drupal Site Configuration: Site Information, Triggers and File System

Packt
08 Sep 2010
9 min read
(For more resources on Drupal, see here.) Not everything that is available in Drupal's Configuration section is discussed in this article. Some settings are very straightforward and really don't warrant more than perhaps a brief mention. Before we start It is sensible to make note of a few important things before getting our hands dirty. Make it second nature to check how the changes made to the settings affect the site. Quite often settings you modify, or features you add, will not behave precisely as expected and without ensuring that you use a prudent approach to making changes, you can sometimes end up with a bit of a mess. Changes to the site's structure (for example, adding new modules) can affect what is and isn't available for configuration so be aware that it may be necessary to revisit this section. Click on Configuration in the toolbar menu. You should see something like the following screenshot: A quick point to mention is that we aren't giving over much space to the final option—Regional and Language. This is because the settings here are very basic and should give you no trouble at all. There is also an online exercise available to help you with date types and formats if you are interested in customizing these. Let's begin! Site information This page contains a mixed bag of settings, some of which are pretty self-explanatory, while others will require us to think quite carefully about what we need to do. To start with, we are presented with a few text boxes that control things like the name of the site and the site slogan. Nothing too earth shattering, although I should point out that different themes implement these settings differently, while some don't implement them at all. For example, adding a slogan in the default Garland theme prints it after the site name as shown in the following screenshot: Whereas, the Stark theme places the slogan beneath the site name: Let's assume that there is a page of content that should be displayed by default—before anyone views any of the other content. For example, if you wanted to display some sort of promotional information or an introduction page, you could tell Drupal to display that using this setting. Remember that you have to create the content for this post first, and then determine its path before you tell Drupal to use it. For example, we could reference a specific node with its node ID, but equally, a site's blogs could be displayed if you substitute node/x (in node/ID format) for the blog. Once you are looking at the content intended for the front page, take note of the relative URL path and simply enter that into the text box provided. Recall that the relative URL path is that part of the page's address that comes after the standard domain, which is shared by the whole site. For example, setting node/2 works because Drupal maps this relative path to http://localhost/drupal/node/2 The first part of this address, http://localhost/drupal/ is the base URL, and everything after that is the relative URL path. Sometimes, the front page is a slightly more complex beast and it is likely that you will want to consider Panels to create a unique front page. In this case, Panels settings can override this setting to make a specific panel page as the front page. The following settings allow you to broadly deal with the problem of two common site errors that may crop up during a site's normal course of operation—from the perspective of a site visitor. In particular, you may wish to create a couple of customized error pages that will be displayed to the users in the event of a "page not found" or "access denied" problem. Remember that there are already pretty concise pages, which are supplied by default. However, if you wish to make any changes, then the process for creating an error page is exactly the same as creating any other normal page. Let's make a change very quickly. Click on Add new content in the Shortcuts menu and select Basic page. Add whatever content you want for, say the Page not found! error: Don't worry about the host of options available on this page—we will talk about all of this later on. For now, simply click on the Save button and make note of the URL of the page when it is displayed. Then head back to the Site information page, add this URL to the Default 404 (not found) page dialog, and then click on the Save configuration button: If you navigate to a page that doesn't exist, for example, node/3333, you should receive the new error message as follows: In this example, we asked Drupal to find a node that does not exist yet and so it displayed the Page not found! error message. Since Drupal can also provide content that is private or available to only certain users, it also needs the access denied error to explain to the would-be users that they do not have sufficient permissions to view the requested page. This is not the same as not finding a page, of course, but you can create your own access denied page in exactly the same way. Finally, you will need to specify how often cron should run in the Automatically run cron drop-down at the bottom of the Site information page. Cronjobs are automated tasks (of any type—they could be search indexing, feed aggregation, and so on) that should run at specified intervals. Drupal uses them to keep itself up-to-date and ensure optimal operation. Drupal uses web page requests to initiate new cron runs once the specified interval has elapsed. If your website does not get visited regularly, cron itself cannot run regularly. Running cron every few hours is reasonable for the vast majority of sites. Setting it to run too quickly can create a huge load on the server because each time the cron is run, all sorts of scripts are updating data, performing tasks, and consuming server resources. By the same token, run cron too infrequently and your site's content can become outdated, or worse, important module, theme, and core updates can go unnoticed, among other things. Actions and triggers Quite often, it happens that for specific events, it is useful to have Drupal automatically perform a specified task or action. An action, in the Drupal sense, is one of a number of tasks that the system can perform, and these usually relate to e-mailing people or acting upon user accounts or content. There are a number of simple actions that are available as well as a few more advanced ones that can be set up by anyone with sufficient permissions. To configure actions, navigate to Actions in SYSTEM under the Configuration menu in the toolbar: Default simple actions cannot be modified, so we will ignore these for the moment and focus on creating a new, advanced action. Set up a new Send e-mail action by selecting it from the drop-down list and click on the Create button, as shown in the preceding screenshot. This brings up the following page that can be set according to how this specific action will be used: It should be clear that the intention of this e-mail is to notify the staff/administration of any new site members. The Label field is important in this respect because this is how you will distinguish this action from the other ones that you may create in the future. Make the description as accurate, meaningful, and concise as possible to avoid any potential confusion. Also notice that there are several placeholder variables that can be inserted into the Recipient, Subject, and Message fields. In this instance, one has been used to inform the e-mail recipient of the new user name, as part of the message. A click on the Save button adds this new action to the list where it can be modified or deleted, accordingly: So far so good—we have set the action, but this in itself does absolutely nothing. An action cannot do anything unless there is a specific system event that can be triggered to set it off. These system events are, perspicaciously enough, called triggers and Drupal can look for any number of triggers, and perform the actions that are associated with it—this is how actions and triggers work together. Triggers are not part of the topic of Drupal configuration. However, we will discuss them here for completeness, since actions and triggers are integrally linked. Triggers are not enabled by default, so head on over to the Modules section and enable the Triggers module. With the module enabled, there will now be a new Triggers link from the Actions page. Clicking on this brings up the following page: Triggers are divided into five different categories, each providing a range of triggers to which actions can be attached. Assigning a trigger is basically selecting an action to apply from the drop-down list of the relevant trigger and clicking on the Assign button. To continue with our example, select the USER tab from the top of the Triggers overlay and, in the TRIGGER: AFTER CREATING A NEW USER ACCOUNT box, select the newly defined action, as shown in the following screenshot: Click on the Assign button, and the newly assigned action will show up in the relevant trigger box: In the same way, a large number of actions can be automated depending on the system event (or trigger) that fires. To test this out, log off and register a new account—you will find that the New User Alert e-mail is dutifully sent out once the account has been registered (assuming your web server is able to send e-mail).
Read more
  • 0
  • 6
  • 7127

article-image-adding-advanced-form-features-using-chronoforms
Packt
31 Aug 2010
16 min read
Save for later

Adding Advanced Form Features using ChronoForms

Packt
31 Aug 2010
16 min read
(For more resources on ChronoForms, see here.) Using PHP to create "select" dropdowns One frequent request is to create a select drop-down from a set of records in a database table. Getting ready You'll need to know the MySQL query to extract the records you need from the database table. This requires some Joomla! knowledge and some MySQL know-how. Joomla! keeps its articles in the jos_content database table and the two-table columns that we want are the article title and the article id. A quick check in the database tells us that the columns are appropriately called title and id. We can also see that the section id column is called sectionid (with no spaces); the column that tells us if the article is published or not is called state and takes the values 1 for published and 0 for not published. How to do it . . . We are going to use some PHP to look up the information about the articles in the database table and then output the results it finds as a series of options for our drop-down box. You'll recall that normal HTML code for a drop-down box looks something like this: <select . . .> <option value='option_value_1'>Option 1 text</option> <option value='option_value_2'>Option 2 text</option> . . .</select> This is simplified a little so that we can see the main parts that concern us here—the options. Each option uses the same code with two variables—a value attribute and a text description. The value will be returned when the form is submitted; the text description is shown when the form is displayed on your site. In simple forms, the value and the description text are often the same. This can be useful if all you are doing with the results is to display them on a web page or in an e-mail. If you are going to use them for anything more complicated than that, it can be much more useful to use a simplified, coded form in the value. For our list of articles, it will be helpful if our form returns the ID of the article rather than its title. Hence, we need to set the options to be something like this: <option value='99'>Article title</option> Having the article ID will let us look up the article in the database and extract any other information that we might need, or to update the record to change the corresponding record. Here's the code that we'll use. The beginning and ending HTML lines are exactly the same as the standard drop-down code that ChronoForms generates but the "option" lines are replaced by the section inside the <?php . . . ?> tags. The PHP snippet looks up the article IDs and titles from the jos_content table, then loops through the results writing an <option> tag for each one: <div class="form_item"> <div class="form_element cf_dropdown"> <label class="cf_label" style="width: 150px;"> Articles</label> <select class="cf_inputbox validate-selection" id="articles" size="1" name="articles"> <option value=''>--?--</option><?phpif (!$mainframe->isSite() ) {return;}$db =& JFactory::getDBO();$query = " SELECT `id`, `title` FROM `#__content` WHERE `sectionid` = 1 AND `state` = 1 ;";$db->setQuery($query);$options = $db->loadAssocList();foreach ( $options as $o ) { echo "<option value='".$o[id]."'>".$o[title]."</option>";}?> </select> </div> <div class="cfclear">&nbsp;</div></div> The resulting HTML will be a standard select drop-down that displays the list of titles and returns the article ID when the form is submitted. Here's what the form input looks like: A few of the options from the page source are shown: <option value='1'>Welcome to Joomla!</option><option value='2'>Newsflash 1</option><option value='3'>Newsflash 2</option>. . . How it works... We are loading the values of the id and title columns from the database record and then using a PHP for each loop to go through the results and add each id and title pair into an <option> tag. There's more... There are many occasions when we want to add select drop-downs into forms with long lists of options. Date and time selectors, country and language lists, and many others are frequently used. We looked here to get the information from a database table which is simple and straightforward when the data is in a table or when the data can conveniently be stored in a table. It is the preferred solution for data such as article titles that can change from day to day. There are a couple of other solutions that can also be useful: Creating numeric options lists directly from PHP Using arrays to manage option lists that change infrequently Creating numeric options lists Let's imagine that we need to create a set of six numeric drop-downs to select: day, month, year, hour, minute, and second. We could clearly do these with manually-created option lists but it soon gets boring creating sixty similar options. There is a PHP method range() that lets us use a similar approach to the one in the recipe. For a range of zero to 60, we can use range(0, 60). Now, the PHP part of our code becomes: <div class="form_item"> <div class="form_element cf_dropdown"> <label class="cf_label" style="width: 150px;"> Minutes</label> <select class="cf_inputbox validate-selection" id="minutes" size="1" name="minutes"> <option value=''>--?--</option><?phpif (!$mainframe->isSite() ) {return;}foreach ( range(0, 60) as $v ) { echo "<option value='$v'>$v</option>";}?> </select> </div> <div class="cfclear">&nbsp;</div></div> This is slightly simpler than the database foreach code, as we don't need the quotes round the array values. This will work very nicely and we could repeat something very similar for each of the other five drop-downs. However, when we think about it, they will all be very similar and that's usually a sign that we can use more PHP to do some of the work for us. Indeed we can create our own little PHP function to output blocks of HTML for us. Looking at this example, there are four things that will change between the blocks—the label text, the name and id, and the range start and the range end. We can set these as variables in a PHP function: <?phpif ( !$mainframe->isSite() ) {return;}function createRangeSelect($label, $name, $start, $end) {?><div class="form_item"> <div class="form_element cf_dropdown"> <label class="cf_label" style="width: 150px;"> <?php echo $label; ?></label> <select class="cf_inputbox validate-selection" id="<?php echo $name; ?>" size="1" name="<?php echo $name; ?>"> <option value=''>--?--</option><?php foreach ( range($start, $end) as $v ) { echo "<option value='$v'>$v</option>"; }?> </select> </div> <div class="cfclear">&nbsp;</div></div><?php}?> Notice that this is very similar to the previous code example. We've added the function . . . line at the start, the } at the end, and replaced the values with variable names. It's important to get the placement of the <?php . . . ?> tags right. Code inside the tags will be treated as PHP, outside them as HTML. All that remains now is to call the function to generate our drop-downs: <?phpif (!$mainframe->isSite() ) {return;}createRangeSelect('Day', 'day', 0, 31);createRangeSelect('Month', 'month', 1, 12);createRangeSelect('Year', 'year', 2000, 2020);createRangeSelect('Hour', 'hour', 0, 24);createRangeSelect('Minute', 'minute', 0, 60);createRangeSelect('Second', 'second', 0, 60);function createRangeSelect($label, $name, $start, $end) {. . . The result tells us that we have more work to do on the layout, but the form elements work perfectly well. Creating a drop-down from an array In the previous example, we used the PHP range() method to generate our options. This works well for numbers but not for text. Imagine that we have to manage a country list. These do change, but not frequently. So they are good candidates for keeping in an array in the Form HTML. It's not too difficult to find pre-created PHP arrays of countries with a little Google research and it's probably easier to use one of these and correct it for your needs than to start from scratch. As we mentioned with the Article list, it's generally simpler and more flexible to use a list with standard IDs (we've used two-letter codes below). With countries, this can remove many problems with special characters and translations. Here are the first few lines of a country list: $countries = array( 'AF'=>'Afghanistan', 'AL'=>'Albania', 'DZ'=>'Algeria', 'AS'=>'American Samoa', . . .); Once we have this, it's easy to modify our foreach . . . loop to use it: foreach ( $countries as $k => $v ) { echo "<option value='$k'>$v</option>";} If you are going to use the country list in more than one form, then it may be worthwhile keeping it in a separate file that is included in the Form HTML. That way, any changes you make will be updated immediately in all of your forms. Using Ajax to look up e-mail addresses It's not very difficult to add Ajax functionality to ChronoForms, but it's not the easiest task in the world either. We'll walk through a fairly simple example here which will provide you with the basic experience to build more complex applications. You will need some knowledge of JavaScript to follow through this recipe. Normally, the only communication between the ChronoForms client (the user in their browser) and the server (the website host) is when a page is loaded or a form is submitted. Form HTML is sent to the client and a $_POST array of results is returned. Ajax is a technique, or a group of techniques, that enables communication while the user is browsing the page without them having to submit the form. As usual, at the browser end the Ajax communication is driven by JavaScript and at the server end we'll be responding using PHP. Put simply, the browser asks a question, the server replies, then the browser shows the reply to the user. For the browser JavaScript and the server PHP to communicate, there needs to be an agreed set of rules about how the information will be packaged. We'll be using the JSON (www.json.org) format. The task we will work on will use a newsletter form. We'll check to see if the user's e-mail is already listed in our user database. This is slightly artificial but the same code can easily be adapted to work with the other database tables and use more complex checks. Getting ready We'll need a form with an e-mail text input. The input id needs to be email for the following code to work: <div class="form_item"> <div class="form_element cf_textbox"> <label class="cf_label" style="width: 150px;">Email</label> <input class="cf_inputbox" maxlength="150" size="30" title="" id="email" name="email" type="text" /> </div> <div class="cfclear">&nbsp;</div></div> The form we use will also have a name text input and a submit button, but they are to make it look like a real form and aren't used in the Ajax coding. How to do it . . . We'll follow the action and start with the user action in the browser. We need to start our check when the user makes an entry in the e-mail input. So, we'll link our JavaScript to the blur event in that input. Here's the core of the code that goes in the Form JavaScript box: / set the url to send the request tovar url = 'index.php?option=com_chronocontact &chronoformname=form_name&task=extra&format=raw';// define 'email'var email = $('email');// set the Ajax call to run// when the email field loses focusemail.addEvent('blur', function() { // Send the JSON request var jSonRequest = new Json.Remote(url, { . . . }).send({'email': email.value});}); Note that the long line starting with var url = . . . &format=raw'; is all one line and should not have any breaks in it. You also need to replace 'form_name' with the name of your form in this URL. There really isn't too much to this. We are using the MooTools JSON functions and they make sending the code very simple. The next step is to look at what happens back on the server. The URL we used in the JavaScript includes the task=extra parameter. When ChronoForms sees this, it will ignore the normal Form Code and instead run the code from the Extra Code boxes at the bottom of the Form Code tab. By default, ChronoForms will execute the code from Extra code 1. If you need to access one of the other boxes, then use for example, task=extra&extraid=3 to run the code from Extra Code box 3. Now, we are working back on the server. So, we need to use PHP to unpack the Ajax message, check the database, and send a message back: <?php// clean up the JSON message$json = stripslashes($_POST['json']);$json = json_decode($json);$email = strtolower(trim($json->email));// check that the email field isn't empty$response = false;if ( $email ) { // Check the database $db =& JFactory::getDBO(); $query = " SELECT COUNT(*) FROM `#__users` WHERE LOWER(`email`) = ".$db->quote($email)."; "; $db->setQuery($query); $response = (bool) !$db->loadResult();}$response = array('email_ok' => $response );//send the replyecho json_encode($response);// stop the from running$MyForm->stopRunning = true;die;?> This code has three main parts: To start with, we "unwrap" the JSON message. Then, we check if it isn't empty and run the database query. Lastly, we package up the reply and tidy up at the end to stop any more form processing from this request. The result we send will be array('email_ok' => $response ) where $response will be either true or false. This is probably the simplest JSON message possible, but is enough for our purpose. Note that here, true means that this e-mail is not listed and is OK to use. The third step is to go back to the form JavaScript and decide how we are going to respond to the JSON reply. Again, we'll keep it simple and just change the background color of the box—red if the e-mail is already in use (or isn't a valid e-mail) or green if the entry isn't in use and is OK to submit. Here's the code snippet to do this using the onComplete parameter of the MooTools JSON function: onComplete: function(r) { // check the result and set the background color if ( r.email_ok ) { email.setStyle('background-color', 'green'); } else { email.setStyle('background-color', 'red'); }} Instead of (or as well as) changing the background color, we could make other CSS changes, display a message, show a pop-up alert, or almost anything else. Lastly let's put the two parts of the client-side JavaScript together with a little more code to make it run smoothly and to check that there is a valid e-mail before sending the JSON request. window.addEvent('domready', function() { // set the url to send the request to var url = 'index.php?option=com_chronocontact &chronoformname=form_name&task=extra&format=raw'; var email = $('email'); email.addEvent('blur', function() { // clear any background color from the input email.setStyle('background-color', 'white'); // check that the email address is valid regex = /^([^@s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})$/i; var value = email.value.trim(); if ( value.length > 6 && regex.test(value) ) { // if all is well send the JSON request var jSonRequest = new Json.Remote(url, { onComplete: function(r) { // check the result and set the background color if ( r.email_ok ) { email.setStyle('background-color', 'green'); } else { email.setStyle('background-color', 'red'); } } }).send({'email': email.value}); } else { // if this isn't a valid email set background color red email.setStyle('background-color', 'red'); } });}); Note that the long line starting with var url = . . . &format=raw'; is all one line and should not have any breaks in it. You also need to replace form_name with the name of your form in this URL. Make sure both the code blocks are in place in the Form JavaScript box and in the Extra Code 1 box, save, and publish your form. Then, test it to make sure that the code is working OK. The Ajax may take a second or two to respond but once you move out of the e-mail, input by tabbing on to another input or clicking somewhere else; the background colour should go red or green. How it works... As far as the Ajax and JSON parts of this are concerned, all we can say here is that it works. You'll need to dig into the MooTools, Ajax, or JSON documents to find out more. From the point of view of ChronoForms, the "clever" bit is the ability to interpret the URL that the Ajax message uses. We ignored most of it at the time but the JavaScript included this long URL (with the query string broken up into separate parameters): index.php?option=com_chronocontact&chronoformname=form_name&task=extra&format=raw The option parameter is the standard Joomla! way to identify which extension to pass the URL to. The chronoformname parameter tells ChronoForms which form to pass the URL to. The task=extra parameter tells ChronoForms that this URL is a little out of the ordinary (you may have noticed that forms usually have &task=send in the onSubmit URL). When ChronoForms sees this, it will pass the URL to the Extra Code box for processing and bypass the usual OnSubmit processing. Lastly, the format=raw parameter tells Joomla! to show the resulting code without any extra formatting and without adding the template code. This means that all that is sent back is just the JSON message. Without it we'd have to dig the message out from loads of surrounding HTML we don't need.
Read more
  • 0
  • 0
  • 5641
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 $19.99/month. Cancel anytime
article-image-using-chronoforms-add-more-features-your-joomla-form
Packt
31 Aug 2010
11 min read
Save for later

Using ChronoForms to add More Features to your Joomla! Form

Packt
31 Aug 2010
11 min read
(For more resources on ChronoForms, see here.) Showing a YouTube video This is the "not really a form" recipe in this article, it just opens a little door to some of the other, more unexpected, capabilities of ChronoForms. For the most part Joomla! protects the content you can display on your pages; it's easy to show HTML + CSS formatted content, more difficult to show PHP and JavaScript. There are many modules, plug-ins and extensions that can help with this but if you have ChronoForms installed then it may be able to help. ChronoForms is designed to show pages that use HTML, CSS, PHP, and JavaScript working together. Most often the pages created are forms but nothing actually requires that any form inputs are included so we can add any code that we like. ChronoForms will wrap our code inside <form>. . .</form> tags which means that we can't embed a form (why would we want to?), but otherwise most things are possible.   Getting ready You will need the ID of the YouTube video that you want to display. We're going to use a video from a conference at Ashridge Business School, but any video will work in essentially the same way. This recipe was developed for this particular video to force display of the HD version. At that time HD was a new option on YouTube and was not readily accessible as it is now. How to do it... Find the video you want on YouTube and look for the links boxes in the right hand column. Here we've clicked on the "customize" icon—the little gear wheel—to open up the options menu. When you've set the options you want copy the code from the Embed box. Here is the code from this video with some added line breaks for clarity: <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/2Ok1SFnMS4E&hl=en_GB&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/2Ok1SFnMS4E&hl=en_GB&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object> To create a good looking page, we are going to add some HTML before and after this snippet: <h3>Video Postcards from the Edge</h3><div>The video of the 2008 AMOC Conference</div><div style='margin:6px; padding:0px; border:6px solid silver;width:425px;'><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/2Ok1SFnMS4E&hl =en&fs=1&ap=%2526fmt%3D18"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/2Ok1SFnMS4E&hl=en&fs =1&ap=%2526fmt%3D18" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></div><div>Some more text . . .</div> If you look closely, you'll see that there is also a new parameter in the URL—&ap=%2526fmt%3D18—which is there to force the HD version of the video to be used. Paste this code into the Form HTML box of a new form, save, and publish it. Of course, it would be entirely possible to embed the video and to add form inputs in the same page, maybe to ask for comments or reviews. How it works... Very simply ChronoForms allows you to embed scripts into the page HTML that are not permitted in standard Joomla! articles. Adding a barcode to a form e-mail Sometimes it's important to add a unique identifier to the form response, for example travel or event tickets. In this recipe we will look at generating a "random" identifier and adding it to the form e-mail as a scannable barcode. Getting ready We're going to need a simple form. Our newsletter form will be perfect although we'll be adding to the code in the Form HTML box. We'll need a simple function to create the "random identifier" which we will see shortly. Lastly we"ll need code to generate a barcode. Rather than taking time reinventing this particular wheel, we're going to use a PHP program created by Charles J Scheffold and made available for use or download from http://www.sid6581.net/cs/php-scripts/barcode/. How to do it... First, grab a copy of the barcode.php file from sid6581.net. We'll need to make this file accessible to our form. So let's create a new folder inside the ChronoForms front-end folder. You'll probably need to use an FTP client to do this, or install the "exTplorer" Joomla! extension which will allow you to create folders from within the Joomla! Site Admin interface. Browse to [root]/components/com_chronocontact and create a new includes folder Copy the standard Joomla! index.html file from the com_chronocontact folder into the new folder Upload the barcode.php file into the new includes folder Now, we are going to add the function to create a "random" identifier to the Form HTML. This is a small function that creates an alphanumeric string when it is called. <?phpif ( !$mainframe->isSite() ) { return; }/* function to generate a random alpha-numeric code using a specified pattern * * @param $pattern string * @return string */function generateIdent($pattern='AA9999A'){ $alpha = array("A","B","C","D","E","F","G","H", "J","K","L","M","N","P","Q","R","S","T","U","V","W", "X","Y","Z"); $digit = array("1","2","3","4","5","6","7","8","9"); $return = ""; $pattern_array = str_split($pattern, 1); foreach ( $pattern_array as $v ) { if ( is_numeric($v) ) { $return .= $digit[array_rand($digit)]; } elseif ( in_array(strtoupper($v), $alpha) ) { $return .= $alpha[array_rand($alpha)]; } else { $return .= " "; } } return $return;}?> We call this function using generateIdent() or generateIdent('pattern') where the pattern is a string of As and 9s that defines the shape of the ident we want. The default is AA9999A, giving idents like KX4629G. This will be perfectly fine for our example here. We also want to add the ident into the form and we'll use a hidden field to do that, but to make it visible we'll also display the value. <?php$ident = generateIdent();echo "<div>Ident is $ident</div>";?><input type='hidden' name='ident' id='ident' value='<?php echo $ident; ?>' /> In day to day use we probably wouldn't generate the ident until after the form is submitted. There is often no useful value in displaying it on the form and essentially the same code will work in the OnSubmit boxes. However, here it makes the process clearer to generate it in the form HTML. We can add both these code snippets to our form just before the submit button element. Then apply or save the form and view it in your browser. The layout may not be very elegant but the Ident is there. Refresh the browser a few times to be sure that it is different each time. It's simpler and tempting to use serial numbers to identify records. If you are saving data in a table then these are generated for you as record IDs. It does create some problems though; in particular, it can make it very easy to guess what other IDs are valid and if, as we often do, we include the ID in a URL it may well be possible to guess what other URLs will be valid. Using a random string like this makes that kind of security breach more difficult and less likely. We said though that we'd generate a barcode, so let's develop this form one more step and show the barcode in the form. If you look at the code in barcode.php, it shows a list of parameters and says what we can use. For example: <img src="barcode.php?barcode=123456&width=320&height=200"> We need to modify this a little to link to the new folder for the file and to add our generated ident value: <img src="/components/com_chronocontact/includes/barcode.php?barcode=<? php echo $ident;?>&width=320&height=8"> This code can go in place of the "echo" line we used to display the ident value: <?php$ident = generateIdent();echo "<img src='".JURI::base()."components/com_chronocontact/includes/barcode.php?barcode=".$ident."&width=320&height=80' />";?> Apply or save the form and view it in your browser. There we have it—a bar code in our form showing the random ident that we have created. If you don't see any graphic and the code appears to be correct then you may not have the PHP GD graphics library installed. Check on the AntiSpam tab for any of your forms and you will see a GD Info box. The GD library is now included in the vast majority of PHP installations. If you don't have it then check with your ISP to see if the library can be enabled. Now that's actually not of much use except to show that it works, you can't scan a bar code off the screen. Where we want it is in our Email template. The code to add to the template is: <div>Your code: {ident}</div><img src="<?php echo JURI::base().'components/com_chronocontact/ includes/'; ?>barcode.php?barcode={ident}&width=280&height=100" /> As this includes some PHP, we can't add it using the Rich Text Editor. First we need to go to the Email Setup | Properties box and set Use Template Editor to No, apply the Properties, then apply the form and go to the Email Template tab. To avoid an "oddity" in the current release of ChronoForms it may be necessary to comment out the generateIdent() function code block in the Form HTML, while you create an Email Setup. Just put /* & */ before and after the block if you get a blank page or see a PHP Error message about re-declaring the function. Now click on the Email Template tab and paste the code at the end of the textarea. Submit the form to test. We now have a printable e-mail complete with a barcode showing our random ident. How it works... In this recipe we did a couple of things. We added some more complex PHP to the Form HTML that we had before and we imported a PHP script found on the internet and successfully used that in combination with ChronoForms. There are many hundreds of useful scripts available for almost any conceivable function. Not all are of good quality and not all will work in this way but, with a little work, a surprising number will function perfectly well. There's more... We said earlier that it might be better to generate the ident after the form is submitted. Here's the code to use in the OnSubmit Before code box to get the same result in the e-mail: <?phpif ( ! $mainframe->isSite() ) { return; }JRequest::setVar('ident', generateIdent());/* function to generate a random alpha-numeric code using a specified pattern * * @param $pattern string * @return string */function generateIdent($pattern='AA9999A'){ $alpha = array("A","B","C","D","E","F","G","H", "J","K","L","M","N","P","Q","R","S","T","U","V","W", "X","Y","Z"); $digit = array("1","2","3","4","5","6","7","8","9"); $return = ""; $pattern_array = str_split($pattern, 1); foreach ( $pattern_array as $v ) { if ( is_numeric($v) ) { $return .= $digit[array_rand($digit)]; } elseif ( in_array(strtoupper($v), $alpha) ) { $return .= $alpha[array_rand($alpha)]; } else { $return .= " "; } } return $return;}?> If you use this, then you can remove all of the additional code from the Form HTML box leaving just the basic HTML generated by the Form Wizard. The Email template code remains as we created it previously.
Read more
  • 0
  • 0
  • 6253

article-image-model-view-controller-pattern-and-configuring-web-scripts-alfresco
Packt
30 Aug 2010
13 min read
Save for later

The Model-View-Controller pattern and Configuring Web Scripts with Alfresco

Packt
30 Aug 2010
13 min read
(For more resources on Alfresco, see here.) One way of looking at the Web Scripts framework is as a platform for implementing RESTful Web Services. Although, as we have seen, your service won't actually be RESTful unless you follow the relevant guiding principles, Web Scripts technology alone does not make your services RESTful as if by magic. Another way of looking at it is as an implementation of the Model-View-Controller, or MVC pattern. Model-View-Controller is a long-established pattern in Computer Science, often used when designing user-facing, data-oriented applications. MVC stipulates that users of the application send commands to it by invoking the controller component, which acts on some sort of data model, then selects an appropriate view for presenting the model to the users. While the applicability of MVC to Web application has often been debated, it is still a useful framework for partitioning concerns and responsibilities and for describing the roles of the various components of the Alfresco Web Scripts framework. In the latter, the role of controller is carried out by the scripting component. It should be stressed that, in the MVC pattern, the controller's role is purely that of governing the user interaction by selecting an appropriate model and a corresponding view for presentation, possibly determining which user actions are applicable given the present state of the application. It is not the controller's role to carry out any kind of business logic or to operate on the model directly. Rather, the controller should always delegate the execution of data manipulation operations and queries to a suitable business logic or persistence layer. In the context of Alfresco Web Scripts, this means that your controller script should avoid doing too many things by using the repository APIs directly. It is the responsibility of the controller to: Validate user inputs Possibly convert them to data types suitable for the underlying logic layers Delegate operations to those layers Take data returned by them Use the data to prepare a model for the view to display and nothing more All complex operations and direct manipulations of repository objects should ideally be carried out by code that resides somewhere else, like in Java Beans or JavaScript libraries, which are included by the present script. In practice, many Web Scripts tend to be quite small and simple, so this strict separation of concerns is not always diligently applied. However, as the size and complexity of controller scripts grows, it is considered as a good practice to modularize an application's logic in order to make it easier to follow and to maintain. Some people also have a preference for the relative safety of a static language like Java, compared to JavaScript, and for the use of modern Java IDEs. Therefore, it is frequent to see Web Scripts applications that place the very minimum of logic in controller scripts that use Java Beans to carry out more complex tasks. Coming to the view, which in Alfresco Web Scripts is implemented as FreeMarker templates, it should be noted that in a departure from the "pure" MVC pattern, the freedom accorded to the controller itself of choice between different possible views is rather limited as which view to use is determined exclusively by selecting a template for the specific output format requested by the user through the format specification in the request URL. The model that the view can access is also only partially the responsibility of the controller. Whereas the latter can add more objects to the model available to the view, it cannot reduce the visibility of the predefined, root-scoped objects. It is therefore possible for the view to perform quite a bit of logic without even having a controller to do it. This is why Web Scripts without a controller are acceptable. Whether this is a good practice or not is open to debate. The following diagram illustrates the steps that are involved when a Web Script is executed: The diagram can be explained as follows: An HTTP request, specifying a method and a URI is received. The dispatcher uses the HTTP method and the URI to select a Web Script to execute and executes the controller script. The controller script accesses the repository services by means of the Alfresco JavaScript API. The model is populated and passed to the FreeMarker template engine for rendering. FreeMarker renders a response using the appropriate template. The response is returned to the client. URL matching We've already seen how the dispatcher selects a particular Web Script by matching the URL of the HTTP request against the value of the url element in the descriptors of the registered Web Scripts. There is actually a bit more to this process than simple, exact matching, as we are going to see. First, let's have a look at the structure of a Web Script's request URL: http[s]://<host>:<port>/[<contextPath>/]/<servicePath>[/ <scriptPath>][?<scriptArgs>] The meaning of host and port should be obvious. contextPath is the name of the web application context, that is, where your application is deployed in your application server or Servlet container. It will often be alfresco, but could be share, as the Share application is able to host Web Scripts. It could be missing, if the application is deployed in the root context, or it could really be anything you want. The value of servicePath will usually be either service or wcservice. Using the former, if the Web Script requires authentication, this is performed using the HTTP Basic method. This means that the browser will pop up a username/password dialog box. When the latter is used, authentication is performed by the Alfresco Explorer (also known as Web Client). This means that no further authentication is required if you are already logged into the Explorer, otherwise you will be redirected to the Explorer login page. scriptPath is the part of the URL that is matched against what is specified in the descriptor. Arguments can optionally be passed to the script by specifying them after the question mark, as with any URL. With this in mind, let's look at the value of the <url> element in the descriptor. This must be a valid URI template, according to the JSR-311 specification. Basically, a URI template is a (possibly relative) URI, parts of which are tokens enclosed between curly braces, such as: /one/two/three /api/login/ticket/{ticket} /api/login?u={username}&pw={password?} Tokens stand for variable portions of the URI and match any value for a path element or a parameter. So, the first template in the previous list only matches /one/two/three exactly, or more precisely: http[s]://<host>:<port>/[<contextPath>/]/<servicePath>/one/two/three The second template here matches any URI that begins with /api/login/ticket/, whereas the third matches the /api/login URI when there is a u parameter present and possibly a pw parameter as well. The ? symbol at the end of a token indicates that the parameter or path element in question is not mandatory. Actually, the mandatory character of a parameter is not enforced by Alfresco, but using the question mark is still valuable for documentation purposes to describe what the Web Script expects to receive. We can now precisely describe the operation of the dispatcher as follows: When the dispatcher needs to select a Web Script to execute, it will select the one matching the specific HTTP method used by the request and whose URI template more specifically matches the script path and arguments contained in the request URL. A Web Script descriptor can also have more than one URI template specified in its descriptor, simply by having more than one <url> element. All of them are consulted for matching. The actual values of the path elements specified as tokens are available to the script as entries in the url.templateArgs map variable. For instance, when the /x/foo URL is matched by the /x/{token} template, the value of the expression url. templateArgs["token"] will be equal to foo. Values of request arguments are accessible from the script or template as properties of the args object, such as args.u and args.pw for the third example here. The format requested, which can be specified in the URL by means of the filename extension or of a format argument, need not be specified in the URI template. Authentication In the last version of our Web Script, we specified a value of user for the <authentication> element. When you use this value, users are required to authenticate when they invoke the Web Script's URL, but they can use any valid credentials. When a value of none is present, the Web Script will not require any authentication and will effectively run anonymously. This tends to not be very useful, as all operations using repository objects will require authentication anyway. If you require no authentication, but try to access the repository anyway, the script will throw an exception. A value of guest requires authentication as the guest user. This can be used for scripts accessed from the Explorer, where users are automatically logged in as guest, unless they log in with a different profile. A value of admin requires authentication as a user with the administrator role, typically admin. Run as Scripts can be run as if they were invoked by a user, other than the one who actually provided the authentication credentials. In order to do this, you need to add a runAs attribute to the <authentication> element: <authentication runAs="admin">user</authentication> This can be used, as in the previous example, to perform operations which require administrator privileges without actually logging in as an admin. As this can be a security risk, only scripts loaded from the Java classpath, and not those loaded from the Data Dictionary, can use this feature. The Login service Web Scripts that render as HTML and are therefore intended to be used by humans directly can either use HTTP Basic authentication or Alfresco Explorer authentication, as it is assumed that some person will fill in a login dialog with his username and password. When a script is meant to implement some form of Web Service that is intended for consumption by another application, HTTP Basic or form-based authentication is not always convenient. For this reason, Alfresco provides the login service, which can be invoked using the following URL: http[s]://<host>:<port>/[<contextPath>/]/service/api/login?u={username }&pw={password?} If authentication is successful, the script returns an XML document with the following type of content: <ticket>TICKET_024d0fd815fe5a2762e40350596a5041ec73742a</ticket> Applications can use the value of the ticket element in subsequent requests in order to avoid having to provide user credentials with each request, simply by adding an alf_ticket=TICKET_024d0fd815fe5a2762e40350596a5041ec73742a argument to the URL. As the username and the password are included, unencrypted, in the request URL, it is recommended that any invocations of the login service be carried out over HTTPS. Transactions Possible values of the transaction element are: none/li> required/li> requiresnew When none is used, scripts are executed without any transactional support. Since most repository operations require a transaction to be active, using none will result in an error whenever the script tries to call repository APIs. required causes the execution of the script to be wrapped in a transaction, which is the normal thing to do. If a transaction is already active when the script is invoked, no new transaction is started. requiresnew, on the other hand, always initiates a new transaction, even if one is already active. Requesting a specific format The format element in the Web Script descriptor indicates how clients are expected to specify which rendering format they require. This is what the element looks like: <format [default="default format"]>extension|argument</format> A value of extension indicates that clients should specify the format as a filename extension appended to the Web Script's path. For example: http://localhost:8080/alfresco/service/myscript.html http://localhost:8080/alfresco/service/myscript.xml A value of argument indicates that the format specification is to be sent as the value of the format URL parameter: http://localhost:8080/alfresco/service/myscript?format=html http://localhost:8080/alfresco/service/myscript?format=xml When the client fails to specify a particular format, the value of the default attribute is taken as the format to use. Once a format has been determined, the corresponding template is selected for rendering the model, after the script finishes its execution, on the basis of the template's filename, which must be of the form: <basename>.<method>.<format>.ftl Status Sometimes it can be necessary for the Web Script to respond to a request with an HTTP status code other than the usual 200 OK status, which indicates that the request has been processed successfully. There might also be a requirement that the response body be different depending on the status code, like, for instance, when you want to display a specific message to indicate that some resource could not be found, together with a status code of 404 Not Found. You can easily do this by manipulating the status object: if (document != null){ status.code = 404 status.message = "No such file found." status.redirect = true} You need to set the value of status.redirect to true in order for Alfresco to use an alternative error handling template. When you do this, the Web Scripts framework goes looking for a template with a file name of <basename>.<method>.<format>.<code>.ftl, like, for instance, myscript.get.html.404.ftl and uses it, if found, instead of the usual myscript.get.html.ftl. In this template, you can access the following properties of the status variable to customize your output: Property name Meaning status.code Numeric value of the HTTP status code (for example, 404) status.codeName String value of the status code (for example, Not Found) status.message Possibly set by the script status.exception The exception that caused this status If your script sets a status code between 300 and 399, which usually means a redirection, you can set the value of status.location to control the value of the location HTTP header: status.code = 301; // Moved permanentlystatus.location = 'http://some.where/else'
Read more
  • 0
  • 0
  • 2761

article-image-overview-rest-concepts-and-developing-your-first-web-script-using-alfresco
Packt
30 Aug 2010
10 min read
Save for later

Overview of REST Concepts and Developing your First Web Script using Alfresco

Packt
30 Aug 2010
10 min read
(For more resources on Alfresco, see here.) Web Scripts allow you to develop entire web applications on Alfresco by using just a scripting language—JavaScript and a templating language—FreeMarker. They offer a lightweight framework for quickly developing even complex interfaces such as Alfresco Share and Web Studio. Besides this, Web Scripts can be used to develop Web Services for giving external applications access to the features of the Alfresco repository. Your Web Services, implemented according to the principles of the REST architectural style, can be easily reused by disparate, heterogeneous systems. Specifically, in this article, you will learn: What REST means and how it compares to SOAP What elements are needed to implement a Web Script A lightweight alternative to SOAP Web Services The term Web Services is generally intended to denote a large family of specifications and protocols, of which SOAP is only a small part, which are often employed to let applications provide and consume services over the World Wide Web (WWW). This basically means exchanging XML messages over HTTP. The main problem with the traditional approach to Web Services is that any implementation has to be compliant with a huge, and complicated set of specifications. This makes the application itself complex and typically hard to understand, debug, and maintain. A whole cottage industry has grown with the purpose of providing the tools necessary for letting developers abstract away this complexity. It is virtually impossible to develop any non-trivial application without these tools based on SOAP. In addition, one or more of the other Web Services standards such as WS-Security, WS-Transaction, or WS-Coordination are required. It is also impossible for any one person to have a reasonably in-depth knowledge of a meaningful portion of the whole Web Services stack (sometimes colloquially referred to as WS-*). Recently, a backlash against this heavyweight approach in providing services over the Web has begun and some people have started pushing for a different paradigm, one that did not completely ignore and disrupt the architecture of the World Wide Web. The main objection that the proponents of the REST architectural style, as this paradigm is called, raise with respect to WS-* is that the use of the term Web in Web Services is fraudulent and misleading. The World Wide Web, they claim, was designed in accordance with REST principles and this is precisely why it was able to become the largest, most scalable information architecture ever realized. WS-*, on the other hand, is nothing more than a revamped, RPC-style message exchange paradigm. It's just CORBA once again, only this time over HTTP and using XML, to put it bluntly. As it has purportedly been demonstrated, this approach will never scale to the size of the World Wide Web, as it gets in the way of important web concerns such as cacheability, the proper usage of the HTTP protocol methods, and of well-known MIME types to decouple clients from servers. Of course, you don't have to buy totally into the REST philosophy—which will be described in the next section—in order to appreciate the elegance, simplicity, and usefulness of Alfresco Web Scripts. After all, Alfresco gives you the choice to use either Web Scripts or the traditional, SOAP-based, Web Services. But you have to keep in mind that the newer and cooler pieces of Alfresco, such as Surf, Share, Web Studio, and the CMIS service, are being developed using Web Scripts. It is, therefore, mandatory that you know how the Web Scripts work, how to develop them, and how to interact with them, if you want to be part of this brave new world of RESTful services. REST concepts The term REST had been introduced by Roy T. Fielding, one of the architects of the HTTP protocol, in his Ph.D dissertation titled Architectural Styles and the Design of Network-based Software Architectures (available online at http://www.ics.uci.edu/ ~fielding/pubs/dissertation/top.htm). Constraints In his work, Dr. Fielding introduces an "architectural style for distributed hypermedia systems" called Representational State Transfer (REST). It does so by starting from an architectural style that does not impose any constraints on implementations (called the Null Style) and progressively adds new constraints that together define what REST is. Those constraints are: Client-Server interaction Statelessness Cacheability Uniform Interface Layered System Code-On-Demand (optional) Fielding then goes on to define the main elements of the REST architectural style. Foremost among those are resources and representations. In contrast with distributed object systems, where data is always hidden behind an interface that only exposes operations that clients may perform on said data, "REST components communicate by transferring a representation of a resource in a format matching one of an evolving set of standard data types, selected dynamically based on the capabilities or desires of the recipient and the nature of the resource." Resources It is important to understand what a resource is and what it isn't. A resource is some information that can be named. It can correspond to a specific entity on a data management system such as a record in a database or a document in a DMS such as Alfresco. However, it can also map to a set of entities, such as a list of search results, or a non-virtual object like a person in the physical world. In any case, a resource is not the underlying entity. Resources need to be named, and in a globally distributed system such as the World Wide Web, they must be identified in a way that guarantees the universality and possibly the univocity of identifiers. On the Web, resources are identified using Uniform Resource Identifiers (URI). A specific category of URIs are Uniform Resource Locators (URL) , which provide a way for clients to locate, that is to find, a resource anywhere on the Web, in addition to identifying it. It is also assumed that URIs never change over the lifetime of a resource, no matter how much the internal state of the underlying entities changes over time. This allows the architecture of the Web to scale immensely, as the system does not need to rely on centralized link servers that maintain references separated from the content. Representations Representations are sequences of bytes intended to capture the current or intended state of a resource, as well as metadata (in the form of name / value pairs) about the resource or the representation itself. The format of a representation is called its media type. Examples of media types are plain text, HTML , XML, JPEG, PDF, and so on. When servers and clients use a set of well-known, standardized media types, interoperability between systems is greatly simplified. Sometimes, it is possible for clients and servers to negotiate a specific format from a set that is supported by both. Control data, which is exchanged between systems together with the representation, is used to determine the purpose of a message or the behavior of any intermediaries. Control data can be used by the client, for instance, to inform the server that the representation being transferred is meant to be the intended new state of the resource, or it can be used by the server to control how proxies, or the client itself, may cache representations. The most obvious example of control data on the Web is HTTP methods and result codes. By using the PUT method, for example, a client usually signals to a server that it is sending an updated representation of the resource. REST in practice As we mentioned, REST is really just an abstract architectural style, not a specific architecture, network protocol, or software system. While no existing system exactly adheres to the full set of REST principles, the World Wide Web is probably the most well-known and successful implementation of them. Developing Web Services that follow the REST paradigm boils down to following a handful of rules and using HTTP the way it was meant to be used. The following sections detail some of those rules. Use URLs to identify resources It is important that you design the URLs for your Web Service in such a way that they identify resources and do not describe the operations performed on said resources. It is a common mistake to use URLs such as: /widgetService/createNewWidget /widgetService/readWidget?id=1 /widgetService/updateWidget?id=1 /widgetService/deleteWidget?id=1 whenever, for instance, you want to design a web service for doing CRUD operations on widgets. A proper, RESTful URL space for this kind of usage scenario could instead be something like the following: /widgets/ To identify a collection of widgets /widgets/id To identify a single widget. Then again, a RESTful interaction with a server that implements the previous service would be along the lines of the following (where we have indicated the HTTP verb together with the URL): POST /widgets/ To create a new widget, whose representation is contained in the body of the request GET /widgets/ To obtain a representation (listing) of all widgets of the collection GET /widgets/1 To obtain a representation of the widget having id=1 POST /widgets/1 To update a widget by sending a new representation (the PUT verb could be used here as well) DELETE /widgets/1 To delete a widget You can see here how URLs representing resources and the appropriate usage of HTTP methods can be used to implement a correctly designed RESTful Web Service for CRUD operations on server-side objects. Use HTTP methods properly There are four main methods that a client can use to tell a server which kind of operation to perform. You can call them commands, if you like. These are GET, POST, PUT, and DELETE. The HTTP 1.1 specification lists some other methods, such as HEAD, TRACE, and OPTIONS, but we can ignore them as they are not frequently used. GET GET is meant to be used for requests that are not intended to modify the state of a resource. This does not mean that the processing by the server of a GET request must be free of side effects—it is perfectly legal, for instance, to increment a counter of page views. GET requests, however, should be idempotent. The property of idempotency means that a sequence of N identical requests should have the same side effects as a single request. The methods GET, HEAD, PUT, and DELETE share this property. Basically, by using GET, a client signals that it intends to retrieve the representation of a resource. The server can perform any operation that causes side effects as part of the execution of the method, but the client cannot be held accountable for them. PUT PUT is generally used to send the modified representation of a resource. It is idempotent as well—multiple, identical PUT requests have the same effect as a single request. DELETE DELETE can be used to request the removal of a resource. This is another idempotent method. POST The POST method is used to request that the server accepts the entity enclosed in the request as a new subordinate of the resource identified by the URI named in the request. POST is a bit like the Swiss army knife of HTTP and can be used for a number of purposes, including: Annotation of existing resources Posting a message to a bulletin board, newsgroup, or mailing list Providing a block of data, such as the result of submitting a form, to a data-handling process Extending a database through an append operation POST is not an idempotent method. One of the main objections proponents of REST raise with respect to traditional Web Service architectures is that, with the latter, POST is used for everything. While you shouldn't feel compelled to use every possible HTTP method in your Web Service (it is perfectly RESTful to use only GET and POST), you should at least know the expectations behind them and use them accordingly.
Read more
  • 0
  • 0
  • 3003

article-image-configuring-and-deploying-ejb-30-entity-weblogic-server
Packt
27 Aug 2010
8 min read
Save for later

Configuring and Deploying the EJB 3.0 Entity in WebLogic Server

Packt
27 Aug 2010
8 min read
(For more resources on Oracle, see here.) Creating a Persistence Configuration file An EJB 3.0 entity bean is required to have a persistence.xml configuration file, which defines the database persistence properties. A persistence.xml file gets added to the META-INF folder when a JPA project is defined. Copy the following listing to the persistence.xml file in Eclipse: <?xml version="1.0" encoding="UTF-8" ?> <persistence xsi_schemaLocation= "http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="em"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>jdbc/MySQLDS</jta-data-source> <class>ejb3.Catalog</class> <properties> <property name="eclipselink.target-server" value="WebLogic_10" /> <property name="javax.persistence.jtaDataSource" value="jdbc/ MySQLDS" /> <property name="eclipselink.ddl-generation" value="create-tables" /> <property name="eclipselink.target-database" value="MySQL" /> </properties> </persistence-unit> </persistence> The persistence-unit is required to be named and may be given any name. We had configured a JDBC data source with JNDI jdbc/MySQLDS in WebLogic Server. Specify the JNDI name in the jta-data-source element. The properties element specifies vendor-specific properties. The eclipselink.ddl-generation property is set to create-tables, which implies that the required database tables will be created unless they are already created . The persistence.xml configuration file is shown in the Eclipse project in the following illustration: (Move the mouse over the image to enlarge.) Creating a session bean For better performance, one of the best practices in developing EJBs is to access entity beans from session beans. Wrapping an entity bean with a session bean reduces the number of remote method calls as a session bean may invoke an entity bean locally. If a client accesses an entity bean directly, each method invocation is a remote method call and incurs an overhead of additional network resources. We shall use a stateless session bean, which consumes less resources than a stateful session bean, to invoke entity bean methods. In this section, we create a session bean in Eclipse. A stateless session bean class is just a Java class annotated with the @Stateless annotation. Therefore, we create Java classes for the session bean and session bean remote interface in Eclipse. To create a Java class, select File | New. In the New window, select Java | Class and click on Next> In the New Java Class window, select the Source folder as EJB3JPA/src, EJB3JPA being the project name. Specify Class Name as CatalogTestBean and click on Finish. Similarly, create a CatalogTestBeanRemote interface by selecting Java | Interface in the New window. The session bean class and the remote interface get added to the EJB3JPA project. The session bean class The stateless session bean class, CatalogTestBean implements the CatalogTestRemote interface. We shall use the EntityManager API to create, find, query, and remove entity instances. Inject an EntityManager using the @PersistenceContext annotation. Specify unitName as the same as the persistence-unit name in the persistence.xml configuration file: @PersistenceContext(unitName = "em") EntityManager em; Next, create a test() method, which we shall invoke from a test client. In the test() method we shall create and persist entity instances, query an entity instance, and delete an entity instance, all using an EntityManager object, which we had injected earlier in the session bean class. Injecting an EntityManager implies that an instance of EntityManager is made available to the session bean. Create an instance of the Entity bean class: Catalog catalog = new Catalog(new Integer(1), "Oracle Magazine", "Oracle Publishing", "September-October 2009", "Put Your Arrays in a Bind","Mark Williams"); Persist the entity instance to the database using the persist() method: em.persist(catalog); Similarly, persist two more entity instances. Next, create a query using the createQuery() method of the EntityManager object. The query string may be specified as a EJB-QL query. Unlike HQL, the SELECT clause is not optional in EJB-QL. Execute the query and return the query result as a List using the getResultList() method. As an example, select the catalog entry corresponding to author David Baum. The FROM clause of a query is directed towards the mapped entity bean class, not the underlying database. List catalogEntry =em.createQuery("SELECT c from Catalog c where c.author=:name").setParameter("name","David Baum"). getResultList(); Iterate over the result list to output the properties of the entity instance: for (Iterator iter = catalogEntry.iterator(); iter.hasNext(); ) { Catalog element = (Catalog)iter.next(); retValue =retValue + "<br/>" + element.getJournal() + "<br/>" + element.getPublisher() +"<br/>" + element.getDate() + "<br/>" + element.getTitle() + "<br/>" + element.getAuthor() +"<br/>"; } The variable retValue is a String that is returned by the test() method. Similarly, create and run a EJB-QL query to return all titles in the Catalog database: List allTitles =em.createQuery("SELECT c from Catalog c"). getResultList(); An entity instance may be removed using the remove() method: em.remove(catalog2); The corresponding database row gets deleted from the Catalog table. Subsequently, create and run a query to list all the entity instances mapped to the database. The session bean class, CatalogTestBean, is listed next: package ejb3; import java.util.Iterator; import java.util.List; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; /** * Session Bean implementation class CatalogTestBean */ @Stateless(mappedName = "EJB3-SessionEJB") public class CatalogTestBean implements CatalogTestBeanRemote { @PersistenceContext(unitName = "em") EntityManager em; /** * Default constructor. */ public CatalogTestBean() { // TODO Auto-generated constructor stub } public String test() { Catalog catalog = new Catalog(new Integer(1), "Oracle Magazine", "Oracle Publishing", "September-October 2009", "Put Your Arrays in a Bind","Mark Williams"); em.persist(catalog); Catalog catalog2 = new Catalog(new Integer(2), "Oracle Magazine", "Oracle Publishing", "September-October 2009", "Oracle Fusion Middleware 11g: The Foundation for Innovation", "David Baum"); em.persist(catalog2); Catalog catalog3 = new Catalog(new Integer(3), "Oracle Magazine", "Oracle Publishing", "September-October 2009", "Integrating Information","David Baum"); em.persist(catalog3); String retValue = "<b>Catalog Entries: </b>"; List catalogEntry = em.createQuery("SELECT c from Catalog c where c.author=:name").setParameter("name", "David Baum").getResultList(); for (Iterator iter = catalogEntry.iterator(); iter.hasNext(); ) { Catalog element = (Catalog)iter.next(); retValue = retValue + "<br/>" + element.getJournal() + "<br/>" + element.getPublisher() + "<br/>" + element.getDate() + "<br/>" + element.getTitle() + "<br/>" + element.getAuthor() + "<br/>"; } retValue = retValue + "<b>All Titles: </b>"; List allTitles = em.createQuery("SELECT c from Catalog c").getResultList(); for (Iterator iter = allTitles.iterator(); iter.hasNext(); ) { Catalog element = (Catalog)iter.next(); retValue = retValue + "<br/>" + element.getTitle() + "<br/>"; } em.remove(catalog2); ); retValue = retValue + "<b>All Entries after removing an entry: </b>"; List allCatalogEntries = em.createQuery("SELECT c from Catalog c"). getResultList(); for (Iterator iter = allCatalogEntries.iterator(); iter.hasNext(); ) { Catalog element = (Catalog)iter.next(); retValue = retValue + "<br/>" + element + "<br/>"; } return retValue; } } We also need to add a remote or a local interface for the session bean: package ejb3; import javax.ejb.Remote; @Remote public interface CatalogTestBeanRemote { public String test(); } The session bean class and the remote interface are shown next: We shall be packaging the entity bean and the session bean in a EJB JAR file, and packaging the JAR file with a WAR file for the EJB 3.0 client into an EAR file as shown next: EAR File | | |-WAR File | |-EJB 3.0 Client |-JAR File | |-EJB 3.0 Entity Bean EJB 3.0 Session Bean Next, we create an application.xml for the EAR file. Create a META-INF folder for the application.xml. Right-click on the EJB3JPA project in Project Explorer and select New>Folder. In the New Folder window, select the EJB3JPA folder and specify the new Folder name as META-INF. Click on Finish. Right-click on the META-INF folder and select New | Other. In the New window, select XML | XML and click on Next. In the New XML File window, select the META-INF folder and specify File name as application.xml. Click on Next. Click on Finish. An application.xml file gets created. Copy the following listing to application.xml: <?xml version = '1.0' encoding = 'windows-1252'?> <application> <display-name></display-name> <module> <ejb>ejb3.jar</ejb> </module> <module> <web> <web-uri>weblogic.war</web-uri> <context-root>weblogic</context-root> </web> </module> </application> The application.xml in the Project Explorer is shown next:
Read more
  • 0
  • 3
  • 9206
article-image-developing-ejb-30-entity-weblogic-server
Packt
27 Aug 2010
3 min read
Save for later

Developing an EJB 3.0 entity in WebLogic Server

Packt
27 Aug 2010
3 min read
(For more resources on Oracle, see here.) Setting the environment In the following sections, we will learn how to set up the environment. Installing required products First, download and install the following required products; when installing the MySQL database, select the option to add the MySQL bin directory to the Windows system PATH environment variable: Oracle WebLogic Server 11g (http://www.oracle.com/technology/software/products/ias/htdocs/wls_main.html). Oracle Enterprise Pack for Eclipse All-In-One edition (http://www.oracle.com/technology/software/products/oepe/oepe_11113.html). MySQL 5.x database (http://www.oracle.com/us/products/mysql/index.html). Creating a MySQL database table Next, create a database table in the MySQL database as follows: Log in to the MySQL database with the following command: >mysql Set database as test: mysql>use test Run the following SQL script, which creates a Catalog table for the EJB 3 entity: CREATE TABLE Catalog (id INT PRIMARY KEY NOT NULL, journal VARCHAR(100), publisher VARCHAR(100), date VARCHAR(100), title VARCHAR(100), author VARCHAR(100)); The output from the CREATE TABLE SQL script is shown in the following screenshot: The table description may be listed with the desc command, as shown in the following illustration: Configuring WebLogic Server with MySQL database We shall be using a MySQL database for persistence. Therefore, we need to create a data source in WebLogic Server. Start the WebLogic Server and log in to the Administration Console. Creating a data source Select the base_domain | Services | JDBC | Data Sources. Click on New in the Data Sources table. Specify a data source name and a JNDI Name (jdbc/MySQLDS) for the data source. Select Database Type as MySQL and Database Driver as MySQL's Driver (Type 4): com.mysql.jdbc.Driver. Click on Next, as shown in the following screenshot: (Move the mouse over the image to enlarge.) In the Transaction Options window, select Supports Global Transactions and One-Phase Commit. Click on Next, as shown in the following screenshot: Specify the connection properties: Database Name as test, Host Name as localhost, Port as 3306, and Database User Name as root. Specify the Password used when installing MySQL and click on Next, as shown in the following screenshot: In the Test Database Connection window, the Driver Class Name and connection URL are specified, normally filled from the information you entered in the previous screen. Click on Test Configuration to test the connection. Click on Finish, as shown in the following screenshot: A data source gets added to the Data Sources table with its data source JNDI Name as jdbc/MySQLDS, as shown in the following screenshot: Deploying the data source Next, we deploy the data source to a target server. Click on the data source link in the Data Sources table and select the Targets tab. Select the AdminServer checkbox and click on Save, as shown in the following screenshot: The target server changes get applied and saved: Testing the data source To test the data source, click on Test Data Source. If the data source tests without an error, a message indicating the same gets displayed as shown next:
Read more
  • 0
  • 0
  • 2531

article-image-styling-your-joomla-form-using-chronoforms
Packt
27 Aug 2010
11 min read
Save for later

Styling your Joomla! form using ChronoForms

Packt
27 Aug 2010
11 min read
(For more resources on ChronoForms, see here.) Introduction Styling forms is more a subject for a book on Joomla! templating, but as not all templates handle it very well, ChronoForms has some basic formatting capabilities that we will look at here. We'll look at two areas—applying CSS to change the "look and feel" of a form and some simple layout changes that may be helpful. We'll be assuming here that you have some knowledge of both CSS and HTML. Using ChronoForms default style ChronoForms recognizes that many Joomla! templates are not strong in their provision of form styling, so it offers some default styling that you can apply (or not) and edit to suit your needs. Getting ready It might be helpful to have a form to look at. Try creating a test form using the ChronoForms Wizard to add "one of each" of the main inputs to a new form and then save it. How to do it... Each of the five steps here describes a different way to style your forms. You can choose the one (or more) that best meets your needs: When you create a form with the Wizard, ChronoForms does three things: Adds some <div> tags to the form HTML to give basic structure Adds classes to the <div> tags and to the input tags to allow CSS styling Loads some default CSS that uses the classes to give the form a presentable layout If you look at the Form HTML created by the Wizard you will see something like this (this is a basic text input): <div class="form_item"> <div class="form_element cf_textbox"> <label class="cf_label" style="width: 150px;"> Click Me to Edit</label> <input class="cf_inputbox" maxlength="150" size="30" title="" id="text_2" name="text_2" type="text" /> </div> <div class="cfclear">&nbsp;</div></div> This example uses the default values from the Wizard. The label text, size, and name may have been changed in the Wizard Properties box. There is a wrapper <div> with a class of form_item. Then, there is a second wrapper around the <label> and <input> tags with two classes—form_element and cf_textbox. There are the <label> and <input> tags themselves with classes of cf_label and cf_inputbox respectively. And lastly there is an "empty" <div> with a class of cfclear that is used to end any CSS floats used in styling the previous tags. The coding for other types of input is very similar, and usually the only difference is the class of the input tag and the <div> tag wrapped around the label and the input. There is nothing very special about any of this; it provides a basic framework for styling. You can't change the default styling used by the Wizard but you can use your own HTML, or edit the Form HTML created by the Wizard. If you change the class names or override the ChronoForms CSS styling with your own styles, then the ChronoForms CSS will no longer apply. Here's what the test form looks like with the default ChronoForms styling: To see the effect of the ChronoForms CSS, open the form in the Form Editor. Go to the General tab, open Core/View Form Settings, and change Load Chronoforms CSS/ JS Files to No. Save the form and refresh the front-end view. Here is the same form without the ChronoForms CSS styling loaded. Not so pretty, but still fully functional. Note: If you create your form in the Form Editor rather than the Wizard, the default setting for Load Chronoforms CSS/JS Files is No. So, you need to turn it on if you want to use the default styling. See also W3Schools CSS tutorials and references at http://www.w3schools.com/css/ default.asp provide a useful online introduction to CSS Switching styles with "Transform Form" The ChronoForms default styling doesn't always suit. So, ChronoForms provides a basic form theming capability. There are only two themes provided—"default" and "theme1". Getting ready We're using the same form as in the previous recipe. How to do it... In the Forms Manager, check the box next to your form name and then click the Transform Form icon in the toolbar. You will see a warning that using Transform Form will overwrite any manual changes to the Form HTML and two form images—one for the "default" theme and one for "theme1". There's a radio button under each theme, and Preview and Transform & Save buttons at the bottom left. The Preview button allows you to see your form with the theme applied. This will not overwrite manual changes; Transform & Save will! Warning: Using Transform & Save will recreate the Form HTML from the version that ChronoForms has saved in the database table. Any manual changes that you have made to the Form HTML will be lost. Applying "theme1" changes the Form HTML structure significantly. Select the "theme1" radio button and click the Preview button to see the result. You can't see this from the preview screen but here's what the text input block now looks like: <div class="cf_item"> <h3 class="cf_title" style="width: 150px;"> Click Me to Edit</h3> <div class="cf_fields"> <input name="text_2" type="text" value="" title="" class="cf_inputtext cf_inputbox" maxlength="150" size="30" id="text_2" /> <br /> <label class="cf_botLabel"></label> </div></div> The wrapping <div> tags and the input are still the same; the old label is now an <h3> tag and there's a new <label> after the input with a cf_botlabel class. The <div> with the cfclear class has gone. This theme may work better with forms that need narrower layouts or where the cfclear <div> tags cause large breaks in the form layout. Neither theme creates a very accessible form layout, and "theme1" is rather less accessible than the "default" theme. If this is important for you then you can create your own form theme. How it works... A ChronoForms theme has two parts—a PHP file that defines the form elements and a CSS file that sets the styling. The Transform Form gets the "Wizard" version of your form that is saved in the database, and regenerates the form HTML using the element structures from the PHP file. When the file is loaded, the theme CSS file will be loaded instead of the default ChronoForms CSS. See also The article "Accessible Forms using WCAG 2.0" (http://www.usability.com.au/resources/wcag2/) is a practical introduction to the topic of web form accessibility. Adding your own CSS styling Many users will want to add their own styling to their forms. This is a short guide about ways to do that. It's not a guide to create the CSS. To add your own Form CSS, you will need to have a working knowledge of HTML and CSS. Getting ready You need nothing to follow the recipe, but when you come to it out, you'll need CSS and a form or two. How to do it... Adding CSS directly in the Form HTML: The quickest and least desirable way of styling is to add CSS directly to the Form HTML. The HTML is accessible on the Form Code tab in the Form Editor. You can type directly into the text area. For example: <input name="text_2" type="text" value="" title="" class="cf_inputtext cf_inputbox" maxlength="150" size="30" id="text_2" style="border: 1px solid blue;" /> The only time when you might need to use this approach is to mark one or two inputs in some special way. Even then it might be better to use a class and define the style outside the Form HTML. Using the Form CSS styles box: In the Form Code tab, ChronoForms has a CSS Styles box, which is opened by clicking the [+/-] link beside CSS Styles. You can add valid CSS definitions in this box (without <style> or </style> tags) and the CSS will be included in the page when it is loaded. For example, you could put this definition into the box: cf_inputbox { border: 1px solid blue; } This will add the following script snippet to the page. If you look at the page source for your form in the front-end you'll find it correctly loaded inside the <head> section. <style type="text/css">cf_inputbox { border: 1px solid blue; } </style> Editing the ChronoForms default CSS: If you have Load Chronoforms CSS/JS Files? set to Yes, then ChronoForms will apply one of its themes, the default one unless you have picked another. The theme CSS files that are used in the front-end are in the components/com_ chronocontact/themes/{theme_name}/css/ folder. Usually there are three files in the folder. The style1-ie6.css file is loaded if the browser detected is IE6; style1-ie7. css is loaded as well for IE7 or IE8; Lstyle1.css is loaded for other browsers. If you edit the ChronoForms CSS, you may need to edit all three files. Note: The themes are duplicated in the Administrator part of ChronoForms, but those files are used in the Transform Form page only. Editing the template CSS: If you want to apply styling more broadly across your site then you may want to integrate the Form CSS with your template style sheets. This is entirely possible; the only thing to make sure of is that the classes in your Form HTML are reflected in the template CSS. You can either manually edit the Form HTML or add the ChronoForms classes to your template styles sheets. Note that this is a much better approach than editing the ChronoForms theme CSS files. Upgrading ChronoForms could well overwrite the theme files. If you have the styles in your template's style sheets, this is not a problem. Creating a new ChronoForms theme is a better solution than editing the default themes as it is protected against overwriting, and allows you to change the layout of the HTML elements in the form. The simplest way to do this is to copy one of the existing theme folders, rename the copy, and edit the files in the new folder. The CSS files are straightforward, but the elements.php file needs a little explanation. If you open the file in an editor, you will find a series of code blocks that define the way in which ChronoForms will structure each of the form elements in the Wizard. Here is an example of a text input: <!--start_cf_textbox--><div class="form_item"> <div class="form_element cf_textbox"> <label class="cf_label"{cf_labeloptions}>{cf_labeltext} </label> <input class="{cf_class}" maxlength="{cf_maxlength}" size="{cf_size}" title="{cf_title}" id="{cf_id}" name="{cf_name}" type="{cf_type}" /> {cf_tooltip} </div> <div class="cfclear">&nbsp;</div></div><!--end_cf_textbox--> The comment lines at the beginning and end mark out this element and must be left intact. Between the comment lines you may add any valid HTML body tags that you like, except that the text input element must include <input type='text' . . . /> and so on. The entries in curly brackets, for example {cf_labeltext}, will be replaced by the corresponding values from the Properties box for this element in the Form Wizard. If they appear they must be exactly the same as the entries in the ChronoForms default theme. Most of the time you will not need to create a new theme, but if you are building Joomla! applications, this provides a very flexible way of letting users create forms with a predetermined structure and style. Note that if you create a new theme, you need to ensure that the files are the same in both theme folders (administrator/ components/com_chronocontact/themes/ and components/com_chronocontact/themes/). Maybe a future version of ChronoForms will remove the duplication.
Read more
  • 0
  • 0
  • 4337

article-image-building-ejb-30-persistence-model-oracle-jdeveloper
Packt
27 Aug 2010
5 min read
Save for later

Building an EJB 3.0 Persistence Model with Oracle JDeveloper

Packt
27 Aug 2010
5 min read
(For more resources on Oracle, see here.) WebLogic server 10.x provides some value-added features to facilitate EJB 3 development. WebLogic server 10.x supports automatic deployment of a persistence unit based on the injected variable's name. The @javax.persistence. PersistenceContext and @javax.persistence.PersistenceUnit annotation s are used to inject the persistence context in an EntityManager or EntityManagerFactory variable . A persistence context is a set of entities that are mapped to a database with a global JNDI name. If the name of the injected variable is the same as the persistence unit, the unitName attribute of the @PersistenceContext or @PersistenceUnit is not required to be specified. The EJB container automatically deploys the persistence unit and sets its JNDI name to be the same as the persistence unit name in persistence.xml. For example, if the persistence unit name in the persistence.xml file is em, an EntityManager variable may be injected with the persistence context as follows: @PeristenceContextprivate EntityManager em; We did not need to specify the unitName attribute in the @PersistenceContext because the variable name is the same as the persistence unit. Similarly, an EntityManagerFactory variable may be injected with the persistence context as follows, emf being also the persistence unit name: @PersistenceUnitprivate EntityManagerFactory emf; Another value-added feature in WebLogic server 10.x is support for vendor-specific subinterfaces of the EntityManager interface. For example, the BEA Kodo persistence provider provides the KodoEntityManager subinterface, which may be injected with the persistence context as follows: @PersistenceContextprivate KodoEntityManager em; Setting the environment Before getting started, we need to install Oracle JDeveloper 11g, which may be downloaded from http://www.oracle.com/technology/products/jdev/index.html. Download the Studio Edition, which is the complete version of JDevloper with all the features. Oracle JDeveloper 11g is distributed as a GUI self-extractor application. Click on the jdevstudio11110 install application. The Oracle Installer gets started. Click on Next in the Oracle Installer. Choose a middleware home directory and click on Next: Choose the Install Type as Complete, which includes the integrated WebLogic Server, and click on Next: Confirm the default Product Installation directories and click on Next: The WebLogic Server installation directory is the wlserver_10.3 folder within the middleware home directory. Choose a shortcut location and click on Next. The Installation Summary lists the products that are installed, which include the WebLogic Server and the WebLogic JDBC drivers. Click on Next to install Oracle JDeveloper 11g and the integrated WebLogic Server 10.3. We also need to install the Oracle database 10g/11g or the lightweight Oracle XE, which may be downloaded from http://www.oracle.com/technology/software/products/database/index.html. When installing Oracle database, also install the sample schemas. Creating a datasource in JDeveloper Next, we create a JDBC datasource in JDeveloper. We shall use the datasource in the EJB 3.0 entity bean for database persistence. First, we need to create a database table in some sample schema, OE for example. Run the following SQL script in SQL *Plus: CREATE TABLE Catalog (id INTEGER PRIMARY KEY NOT NULL,journal VARCHAR(100), publisher VARCHAR(100), edition VARCHAR(100),title VARCHAR(100), author VARCHAR(100)); A database table gets created in the OE sample schema. Next, we need to create a JDBC connection in JDeveloper with Oracle database. Open the Database Navigator or select the Database Navigator tab if already open. Right-click on the IDE Connections node and select New Connection: In the Create Database Connection window, specify a Connection Name, select Connection Type as Oracle (JDBC), specify Username as OE, which is the schema in which the Catalog table is created, and specify the password for the OE schema. Select Driver as thin, Host Name as localhost, SID as ORCL, and JDBC Port as 1521. Click on the Test Connection button to test the connection. If the connection gets established, click on OK: The OracleDBConnection gets added to the Database Navigator view. The CATALOG table that we created is listed in the Tables: (Move the mouse over the image to enlarge.) Creating an EJB 3 application In this section, we create an EJB 3.0 application in JDeveloper. Select New Application: Specify an Application Name, select the Java EE Web Application template, which consists of a Model project and a ViewController project, and click on Next: Next, specify the name (EJB3ViewController) for the View and Controller project. In the Project Technologies tab, transfer the EJB project technology from the Available list to the Selected list using the > button. We have selected the EJB project technology, as we shall be creating an EJB 3.0 model. Click on Next: Select the default Java settings for the View project and click on Next: Configure the EJB Settings for the View project. Select EJB Version as Enterprise JavaBeans 3.0 and select Using Annotations. Click on Next. Next, create the Model project. Specify the Project Name (EJB3Model for example), and in the Project Technologies tab transfer the EJB project technology from the Available list to the Selected list using the > button. We have added the EJB project technology, as the EJB 3.0 application client is created in the View project. Click on Next: Select the default Java settings for the Model project and click on Next: Similar to the View project, configure the EJB settings for the Model project. Select EJB Version as Enterprise JavaBeans 3.0, select Using Annotations and click on Finish. As we won't be using a jndi.properties file or an ejb-jar.xml file , we don't need to select the generate option for the jndi.properties file and the ejb-jar.xml file: An EJB 3.0 application, which consists of a Model project and a ViewController project, get added in the Application tab: Select the EJB3Model project in the Application navigator and select Tools | Project Properties. In the Project Properties window, select the Libraries and Classpath node. The EJB 3.0 library should be in the Classpath Entries: Select the EJB Module node and select the OracleDBConnection in the Connection drop-down list. The datasource corresponding to the OracleDBConnection is jdbc/OracleDBConnectionDS.
Read more
  • 0
  • 0
  • 3263
article-image-syntax-validation-javascript-testing
Packt
26 Aug 2010
10 min read
Save for later

Syntax Validation in JavaScript Testing

Packt
26 Aug 2010
10 min read
(For more resources on JavaScript, see here.) So without further ado, let us get started with a lighter topic—the difference between validating and testing. The difference between validating and testing There's a thin line separating validating and testing. If you have some idea about sets (as in sets from mathematics), I would say that validation can lead to better testing results, while testing does not necessarily lead to a valid code. Let us consider the scenario—you wrote a JavaScript program and tested it on major browsers such as the Internet Explorer and Firefox; and it worked. In this case, you have tested the code to make sure that it is functional. However, the same code that you have created may or may not be valid; valid code is akin to writing a code that has the following characteristics: Well formed Has good coding style (such as proper indentation, well-commented code, properly spaced) Meets the specification of the language (in our case, JavaScript) There may come a point in time where you will notice that good coding style is highly subjective—there are various validators that may have different opinions or standards as to what is known as "good coding style". Therefore, if you do use different validators to validate your code, do not freak out if you see different advice for your coding style. This does not mean that valid code leads to code that is functional (as you will see later) and that code that is functional leads to validated code as both have different standards for comparison. However, valid code often leads to less errors, and code that is both functional and valid is often quality code. This is due to the fact that writing a piece of JavaScript code, that is both valid and correct, is much more difficult than just writing a code that is correct. Testing often means that we are trying to get the code working correctly; while validation is making sure that the code is syntactically correct, with good style and that it meets the specification of the language. While good coding styles may be subjective, there is often a coding style that is accepted by most programmers, such as, making sure that the code is properly commented, indented, and there is no pollution of the global namespace (especially in the case of JavaScript). To make the case clearer, following are three situations that you can consider: Code that is valid but wrong–validation doesn't find all the errors This form of errors would most probably be caused by logic errors in JavaScript. Logic errors can be syntactically correct but they may be logically flawed. A classic example would be an infinite for loop or infinite while loop. Code that is invalid but right This would most probably be the case for most functional code; a piece of JavaScript may be functionally correct and working, but it may be invalid. This may be due to poor coding style or any other characteristics in a valid code that are missing. Later on in this article, you will see a full working example of a piece of JavaScript code that is right but invalid. Code that is invalid and wrong–validation finds some errors that might be difficult to spot any other way In this case, the code error can be caused by all three forms of JavaScript errors that are mentioned in the article such as loading errors, runtime errors, and logic errors. While it is more likely that errors caused by syntax errors might be spotted by good validators, it is also possible that some errors are buried deep inside the code, such that it is difficult to spot them using manual methods. Now that we have some common understanding as to what validation and testing is about, let us move on to the next section which discusses the issues surrounding quality code. Code quality While there are many views as to what is quality code, I personally believe that there are a few agreed standards. Some of the most commonly mentioned standards may include code readability, ease of extension, efficiency, good coding style, and meeting language specifications, and so on. For our purpose here, we will focus on the factors that make a piece of code valid—coding style and meeting specifications. In general, good coding style almost guarantees that the code is highly readable (even to third parties) and this will help us to spot errors manually. Most importantly, having a good coding style allows us to quickly understand the code, specially if we need to work in teams or are required to debug the code on our own. You will notice that we will focus on the importance of code validity for testing purposes in later parts of the article. But now, let us start with the first building block of quality code—valid HTML and CSS. HTML and CSS needs to be valid before you start on JavaScript We have a common understanding that JavaScript breathes life into a web page by manipulating the Document Object Model (DOM) of the HTML documents. This means that the DOM must be present in the code before JavaScript can operate on it. Here's an important fact that is directly related to HTML, CSS, and browsers—browsers are generally forgiving towards invalid HTML and CSS code as compared to compilers for languages like C or Python. This is because, all browsers have to do is parse the HTML and CSS so as to render the web page for its browsers. On the other hand, compilers are generally unforgiving towards invalid code. Any missing tag, declarations, and so on will lead to a compilation error. Therefore, it is ok to write invalid or even buggy HTML and CSS, yet get a "usual" looking web page. Based on the previous explanation, we should see that we would need to have valid HTML and CSS in order to create quality JavaScript code. A short list of reasons, based on my personal experience, as to why valid HTML and CSS is an important prerequisite before you start working on JavaScript are as follows: Valid HTML and CSS helps ensure that JavaScript works as intended. For example, consider a situation where you might have two div elements that have the same id , code that is supposed to work on the above mentioned HTML element with the id. This will result in unintended consequences. Valid HTML and CSS helps improve the predictability on how your web page will work; there is no point trying to fi x buggy HTML or CSS using JavaScript. You are most probably better off if you start with valid HTML and CSS, and then apply JavaScript. Invalid HTML and CSS may result in different behaviour in different browsers. For example, an HTML tag that is not enclosed may be rendered differently in different browsers. In short, one of the most important building blocks of creating quality JavaScript code is to have valid HTML and CSS. What happens if you don't validate your code You may disagree with me on the previous section as to why HTML and CSS should be valid. In general, validation helps you to prevent errors that are related to coding style and specifications. However, do take note that using different validators may give you different results since validators might have different standards in terms of code style. In case you are wondering if invalid code can affect your JavaScript code, I would advise you to make your code as valid as possible; invalid code may lead to sticky issues such as cross-browser incompatibility, difficulty in reading code, and so on. Invalidated code means that your code may not be foolproof; in the early days of the Internet, there were websites that were dependent on the quirks of the early Netscape browser. Back track to the time where the Internet Explorer 6 was widely used, there were also many websites that worked in quirks mode to support Internet Explorer 6. Now, most browsers are supporting or are moving towards supporting web standards (though slightly different, they are supporting in subtle manners), writing valid code is one of the best ways to ensure that your website works and appears the way it is intended to. How validation can simplify testing While invalid code may not cause your code to be dysfunctional, valid code often simplifies testing. This is due to the focus on coding style and specifications; codes that are valid and have met specifications are typically more likely to be correct and much easier to debug. Consider the following code that is stylistically invalid: function checkForm(formObj){alert(formObj.id)//alert(formObj.text.value);var totalFormNumber = document.forms.length;// check if form elements are empty and are digitsvar maxCounter = formObj.length; // this is for checking for emptyvaluesalert(totalFormNumber);// check if the form is properly filled in order to proceedif(checkInput(formObj)== false){alert("Fields cannot be empty and it must be digits!");// stop executing the code since the input is invalidreturn false;}else{;}var i = 0;var formID;while(i < totalFormNumber){if(formObj == document.forms[i]){formID = i;alert(i);}i++;}if(formID<4){formID++;var formToBeChanged = document.forms[formID].id;// alert(formToBeChanged);showForm(formToBeChanged);}else{// this else statement deals with the last form// and we need to manipulate other HTML elementsdocument.getElementById("formResponse").style.visibility = "visible";}return false;} The previous code is an extreme example of poor code style, especially in terms of indentation. Imagine if you have to manually debug the second code snippet that you saw earlier! I am pretty sure that you will find it frustrating to check the code, because you will have little visual sense of what is going on. More importantly, if you are working in a team, you will be required to write legible code; in short, writing valid code typically leads to code that is more legible, easier to follow, and hence, less erroneous. Validation can help you debug your code As mentioned in the previous section, browsers are in general forgiving towards invalid HTML and CSS. While this is true, there may be errors that are not caught, or are not rendered correctly or gracefully. This means that while the invalid HTML and CSS code may appear fine on a certain platform or browser, it may not be supported on others. This means that using valid code (valid code typically means standard code set by international organizations such as W3C) will give you a much greater probability of having your web page rendered correctly on different browsers and platforms. With valid HTML and CSS, you can safely write your JavaScript code and expect it to work as intended, assuming that your JavaScript code is equally valid and error free. Validation helps you to code using good practices Valid code typically requires coding using good practices. As mentioned frequently in this article, good practices include the proper enclosing of tags, suitable indentation to enhance code readability, and so on. If you need more information about good practi ces when using JavaScript, feel free to check out the creator of JSLint, Douglas Crockford, at http://crockford.com.. Or you can read up John Resigs blog (the creator of JQuery) at http://ejohn.org. Both are great guys who know what great JavaScript is about. Validation To summarize the above sections, the DOM is provided by HTML, and both CSS and JavaScript are applied to the DOM. This means that if there is an invalid DOM, there is a chance that the JavaScript that is operating on the DOM (and sometimes the CSS) might result in errors. With this summary in mind, we'll focus on how you can spot validation errors by using color coding editors.
Read more
  • 0
  • 0
  • 3764

article-image-trapping-errors-using-built-objects-javascript-testing
Packt
25 Aug 2010
6 min read
Save for later

Trapping Errors by Using Built-In Objects in JavaScript Testing

Packt
25 Aug 2010
6 min read
(For more resources on JavaScript, see here.) The Error object An Error is a generic exception, and it accepts an optional message that provides details of the exception. We can use the Error object by using the following syntax: new Error(message); // message can be a string or an integer Here's an example that shows the Error object in action. The source code for this example can be found in the file error-object.html. <html><head><script type="text/javascript">function factorial(x) { if(x == 0) { return 1; } else { return x * factorial(x-1); } } try { var a = prompt("Please enter a positive integer", ""); if(a < 0){ var error = new Error(1); alert(error.message); alert(error.name); throw error; } else if(isNaN(a)){ var error = new Error("it must be a number"); alert(error.message); alert(error.name); throw error; } var f = factorial(a); alert(a + "! = " + f); } catch (error) { if(error.message == 1) { alert("value cannot be negative"); } else if(error.message == "it must be a number") { alert("value must be a number"); } else throw error; } finally { alert("ok, all is done!"); } </script> </head> <body> </body> </html> You may have noticed that the structure of this code is similar to the previous examples, in which we demonstrated try, catch, finally, and throw. In this example, we have made use of what we have learned, and instead of throwing the error directly, we have used the Error object. I need you to focus on the code given above. Notice that we have used an integer and a string as the message argument for var error, namely new Error(1) and new Error("it must be a number"). Take note that we can make use of alert() to create a pop-up window to inform the user of the error that has occurred and the name of the error, which is Error, as it is an Error object. Similarly, we can make use of the message property to create program logic for the appropriate error message. It is important to see how the Error object works, as the following built-in objects, which we are going to learn about, work similarly to how we have seen for the Error object. (We might be able to show how we can use these errors in the console log.) The RangeError object A RangeError occurs when a number is out of its appropriate range. The syntax is similar to what we have seen for the Error object. Here's the syntax for RangeError: new RangeError(message); message can either be a string or an integer. <html><head><script type="text/javascript">try { var anArray = new Array(-1); // an array length must be positive}catch (error) { alert(error.message); alert(error.name);}finally { alert("ok, all is done!");}</script></head><body></body></html> We'll start with a simple example to show how this works. Check out the following code that can be found in the source code folder, in the file rangeerror.html: When you run this example, you should see an alert window informing you that the array is of an invalid length. After this alert window, you should receive another alert window telling you that The error is RangeError, as this is a RangeError object. If you look at the code carefully, you will see that I have deliberately created this error by giving a negative value to the array's length (array's length must be positive). The ReferenceError object A ReferenceError occurs when a variable, object, function, or array that you have referenced does not exist. The syntax is similar to what you have seen so far and it is as follows: new ReferenceError(message); message can either be a string or an integer. As this is pretty straightforward, I'll dive right into the next example. The code for the following example can be found in the source code folder, in the file referenceerror.html. <html><head><script type="text/javascript">try { x = y; // notice that y is not defined // an array length must be positive}catch (error) { alert(error); alert(error.message); alert(error.name);}finally { alert("ok, all is done!");}</script></head><body></body></html> Take note that y is not defined, and we are expecting to catch this error in the catch block. Now try the previous example in your Firefox browser. You should receive four alert windows regarding the errors, with each window giving you a different message. The messages are as follows: ReferenceError: y is not defined y is not defined ReferenceError ok, all is done If you are using Internet Explorer, you will receive slightly different messages. You will see the following messages: [object Error] message y is undefined TypeError ok, all is done The TypeError object A TypeError is thrown when we try to access a value that is of the wrong type. The syntax is as follows: new TypeError(message); // message can be a string or an integer and it is optional An example of TypeError is as follows: <html><head><script type="text/javascript">try { y = 1 var test = function weird() { var foo = "weird string"; } y = test.foo(); // foo is not a function}catch (error) { alert(error); alert(error.message); alert(error.name);}finally { alert("ok, all is done!");}</script></head><body></body></html> If you try running this code in Firefox, you should receive an alert box stating that it is a TypeError. This is because test.foo() is not a function, and this results in a TypeError. JavaScript is capable of finding out what kind of error has been caught. Similarly, you can use the traditional method of throwing your own TypeError(), by uncommenting the code. The following built-in objects are less used, so we'll just move through quickly with the syntax of the built-in objects.
Read more
  • 0
  • 0
  • 5505
Modal Close icon
Modal Close icon