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
All 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

1797 Articles
article-image-manipulation-dom-objects-using-firebug
Packt
16 Apr 2010
3 min read
Save for later

Manipulation of DOM Objects using Firebug

Packt
16 Apr 2010
3 min read
Inspecting DOM The DOM inspector allows for full, in-place editing of our document structure, not just text nodes. In the DOM inspector, Firebug auto completes property value when we press the Tab key. The following are the steps to inspect an element under the DOM tab: Press Ctrl+Shift+C—the shortcut key to open Firebug in inspect mode. Let's move the mouse pointer over the HTML element that we want to inspect and click on that element. The HTML script of that element will be shown in Firebug's HTML tab. Right-clicking on the selected DOM element will open a context menu. Let's select the Inspect in DOM Tab option from the context menu. As soon as we do that, Firebug will take us to its DOM tab. Filtering properties, functions, and constants Many times we want to analyze whether a function written by us is associated with an HTML element. Firebug provides us an easy way to figure out whether an event, listener, function, property, or constants are associated with a particular element. The DOM tab is not only a tab but also a drop-down menu. When we click on the down arrow icon on the DOM tab, Firebug will show a drop-down list from which one can select the filtering options and inspect the element thoroughly. The following are the options provided by this menu: Show User-defined Properties Show User-defined Functions Show DOM Properties Show DOM Functions Show DOM Constants Refresh There are two kinds of objects and functions: Part of the standard DOM Part of our own JavaScript code Firebug can notify the difference, and shows us our own script-created objects and functions in bold at the top of the list. The text that is bold and green is a user-defined function. The text that is bold and black is a user-defined property. The text whose size is normal and is green in color is a DOM-defined function. The text whose size is normal and is black in color is a DOM-defined property. The upper case letters (capital letters) are the DOM constants. We can see the actual colored depiction in Firebug's DOM tab. In the following code, the onkeyup() event is a user-defined function for <input/> and calculatefactorial() is a user-defined function for the current window. To test this code, let's type the code in an HTML file, open it with Firefox, and enable Firebug by pressing the F12 key. Inspect the input element in the DOM. <html><head><script>function calculateFactorial(num,event){if(event.keyCode!=13){return;}var fact=1;for(i=1;i<=num;i++){fact*=i;}alert ("The Factorial of "+ num + " is: " +fact)}</script><title>code_6_1.html.html</title></head><body><font face="monospace">Enter a number to calculate its factorial<input type = "text" name="searchBox" onkeyup="calculateFactorial(this.value,event)"/></font></body></html> Intuitive DOM element summariesThere are many different kinds of DOM and JavaScript objects, and Firebug does its best to visually distinguish each, while providing as much information as possible. When appropriate, objects include brief summaries of their contents so that we can see what's there without having to click. Objects are color coded so that HTML elements, numbers, strings, functions, arrays, objects, and nulls are all easy to distinguish.
Read more
  • 0
  • 0
  • 2560

article-image-getting-started-development-environment-using-microsoft-content-management-server
Packt
15 Apr 2010
8 min read
Save for later

Getting Started with the Development Environment Using Microsoft Content Management Server

Packt
15 Apr 2010
8 min read
Visual Web Developer Websites The key difference between developing MCMS applications with Visual Studio .NET 2003 and Visual Studio 2005 is that ASP.NET applications (and therefore MCMS applications) are now built using the Visual Web Developer component of Visual Studio 2005. Visual Web Developer introduces a new "project system", which no longer uses the project (*.csproj) files and simply accesses web applications via HTTP or the file system. In Visual Studio .NET 2003, MCMS applications were created by choosing the MCMS Web Application project type. This project type was effectively a regular ASP.NET web application project with some modifications required by MCMS, such as additional references, the web authoring console, and modifications to the web.config. In Visual Studio 2005, developing web applications has been separated from developing other project types. The feature to develop a web application has been moved into the Visual Web Developer component. To reflect this design change, you are no longer using New Project but New Web Site from the File menu in Visual Studio 2005 to create a new website. Visual Studio 2005 ships with several website templates. The installation of the developer tools for MCMS extends the list of website templates with three additional templates: MCMS Empty Web Project, MCMS Web Application, and MCMS Web Service. These templates are actually modified versions of the similarly named standard templates shipped with Visual Studio 2005. Creating an MCMS Web Application Let's create an MCMS web application using Visual Studio 2005. Open Visual Studio 2005. From the File menu, choose New, followed by Web Site… In the New Web Site dialog, select the MCMS Web Application within the My Templates section. If the MCMS Web Application template does not appear in the My Templates section, the MCMS Visual Studio 2005 templates have not been correctly installed. Please refer to the Visual Studio Templates section of Article 1 for installation details. In the Location combo box, select HTTP, and in the textbox, enter http://localhost/mcmstest. MCMS applications have to be created using a local installation of IIS and do not support being created using the file system, which makes use of the built-in Visual Web Developer Web Server. Note that the New Web Site wizard will not prevent you from configuring an invalid website using the File System and Visual Web Developer Web Server. In the Language combo box (shown in the following figure), select Visual C#, and click on OK. If you wish, you can also choose VB.NET. The samples in this article series are all written in Visual C#. Visual Studio 2005 will create your project and initialize the MCMS Template Explorer. When it's done, you will be presented with an MCMS website with the basic foundation files. The MCMS Template Explorer within Visual Studio 2005 logs on to the MCMS repository using the credentials of the currently logged-on user. If this operation fails, check your MCMS Rights Groups configuration. The Template Explorer does not allow you to specify alternative credentials. Click on the MCMS Template Explorer tab at the bottom of the Solution Explorer, and note that the Template Gallery is accessible. If you don't see the Template Explorer, it is likely you didn't select HTTP in the Location combo box in step 4. You may also not see the Template Explorer if you are using a locale other than US English, in which case you need to install hotfix 914195 as detailed in Article 1. Click on the Solution Explorer tab at the bottom of the MCMS Template Explorer, and click on the Refresh button. Notice that unlike the web applications from ASP.NET 1.x days, the 'CMS' virtual directory is now part of the website. If you examine the contents of the website, its references, and web.config file, you will see that the necessary MCMS files and configuration changes have been added. Checking the Website Configuration Settings in IIS We can verify that Visual Studio 2005 has configured the MCMS application correctly by using the Internet Information Services snap-in. First, let's ensure that the mcmstest website is indeed running on ASP.NET 2.0. From the Start Menu click on Run, enter inetmgr in the Run textbox, and click on OK. In Internet Information Services, expand the tree view to display the mcmstest application. Right-click the mcmstest application and click on Properties. Click the ASP.NET tab and note that the ASP.NET version is correctly configured as 2.0.50727. When developing on Windows Server 2003, the Virtual Website root must run in the same worker process (that is Application Pool) as all MCMS applications so that the MCMS ISAPI Filter can work as expected. This filter cannot route requests across worker-process boundaries. In effect this means that all MCMS applications will share the same ASP.NET version, as ASP.NET does not support side-by-side execution of different versions inside the same worker process. This is not necessary with IIS on Windows XP as it does not use Worker Process Isolation mode. Next, we will check the authentication settings. For now, we will configure the website to use integrated Windows authentication. Only users with a domain or local user account will have access to the site. Later in Article 6 we will show alternative authentication methods such as Forms Authentication. Click on the Directory Security tab followed by the Edit... button, and note that the permissions are correctly inherited from the Virtual Web Site settings. In this example, we will use integrated Windows authentication. Note that we configured the Virtual Web Site to use Windows authentication in Article 1. Authentication methods can be configured on a per-application basis. Click on Cancel and close Internet Information Services. Developing MCMS Web Applications We are now ready to get started on developing our ASP.NET 2.0-based MCMS applications. There are a number of quirks with the MCMS web application templates, which we need to bear in mind during development. Switch back to Visual Studio 2005. In Solution Explorer, right-click on the website (http://localhost/mcmstest), and click on New Folder. Enter Templates as the folder name. Right-click on the Templates folder and click on Add New Item… In the Add New Item dialog, select the MCMS Template File item and enter Basic.aspx in the Name textbox. Click on Add. The new Basic.aspx template file is created and opened in Source View. Examine the contents of Basic.aspx. Correcting Basic.aspx Notice that the Basic.aspx file has a few problems. Some elements are highlighted by IntelliSense "squiggles", and if we attempt to build the website, a number of errors will prevent a successful build. Let's correct the Basic.aspx template file. In the CodeFile attribute of the Page directive on line one, replace CodeFile="~/Basic.aspx.cs" with CodeFile="basic.aspx.cs" The MCMS Web Application New Item template doesn't recognize that our new template file has been created in a subdirectory, and therefore the CodeFile attribute is incorrect. New templates in the web root are not affected. From the Build menu, choose Build Web Site. Notice that the website now builds, but still includes a number of errors. Correct the DOCTYPE. On line 19, replace <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"> with <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> Correct the <html> element. On line 20, replace <html> with <html >. Delete the comments on lines 4 through 17. The comments within an inline ASP script block (<% %>) are unnecessary. Delete the <meta> tags on lines 10 through 13. <meta name="GENERATOR" content="Microsoft Visual Studio .NET 8.0"><meta name="CODE_LANGUAGE" content="C#"><meta name="vs_defaultClientScript" content="JavaScript"><meta name="vs_targetSchema"content="http://schemas.microsoft.com/intellisense/ie5"> These <meta> tags are unnecessary. Correct the WebControls Register directive. On line 2, replace: <%@ Register TagPrefix="cms" Namespace="MicrosoftContentManagement.WebControls" Assembly="Microsoft.ContentManagement.WebControls"%> with <%@ Register Assembly="Microsoft.ContentManagement.WebControls,Version=5.0.1200.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="Microsoft.ContentManagement.WebControls"TagPrefix="cms"%> The original Register directive is not correctly recognized by Visual Studio 2005, and prevents IntelliSense from including the cms tag prefix. From the Build menu, choose Build Web Site. Notice that the website now builds free of any errors and that the cms tag prefix is understood. Your template file should now be as follows: <%@ Page language="c#" AutoEventWireup="false" CodeFile="Basic.aspx.cs" Inherits="Basic.Basic"%><%@ Register Assembly="Microsoft.ContentManagement.WebControls,Version=5.0.1200.0, Culture=neutral, PublicKeyToken= 31bf3856ad364e35"Namespace="Microsoft.ContentManagement.WebControls"TagPrefix="cms"%><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html > <head> <title>Basic</title> <cms:RobotMetaTag runat="server"></cms:RobotMetaTag> </head> <body> <form id="Form1" method="post" runat="server"> </form> </body></html>
Read more
  • 0
  • 0
  • 1107

article-image-creating-tumblr-theme
Packt
15 Apr 2010
13 min read
Save for later

Creating a Tumblr Theme

Packt
15 Apr 2010
13 min read
At this moment, surely, you must have heard something about Tumblr, but in case you haven't, we can summarize by telling it's a platform for microblogging. We can publish texts, audio, photos, quotes, links etc in a very easy way. As other users can follow our posts, comment on them or ask questions to us, Tumblr can be considered a great social tool. Apart from being very easy to use, we can also customize it's appearance, so it shares our business look and feel, or simply because we prefer some other appearance. Not only can we customize it's appearance, but also design our own customized themes; that's exactly what we are going to do in this article: What we have and what we want First steps, a basic html template Generating the Tumblr theme from our template Adding a bit of jQuery Keep with us and by the end of the article, you will learn how to create very interesting Tumblr themes, and use also them. What we have and what we want For this article, we are going to use my own account as an example. For now, I'm using a theme that looks this way: This is a great theme, very clean, centered on showing our content. The theme we are going to create is going to be very clean too, and also enough for us to see how we can create a template. Let's take a look at it: As you can see, it's a quite easy design; hope you like it too. Also, you can download the PSD if you wish, maybe it will help you follow the article. Well, once we know which design we want to use, our next step will be to generate a plain html template. First step, a basic html template A basic html template is a good place to start our theme, and that's where we are going to start. First the basic structure: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html ><head> <title>Our first theme</title> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> </head> <body id="theme"> <div id="container"> <div id="menu"> <a href="#" class="menu_link">About me</a> | <a href="#" class="menu_link">Archives</a> | <a href="#" class="menu_link">Random</a> | <a href="#" class="menu_link">Mobile</a> | <a href="#" class="menu_link">RSS</a> </div> <div id="right_col"> <div class="post"> <div class="post_type"> <div class="blue_box">Text</div> <a href="#" class="content_link">Permalink</a> </div> <div class="date"> <div class="blue_box">Mar 22</div> Posted at 7:54am </div> <div class="post_contents"> <h1>Codeigniter 1.7</h1> <p> <img src="sample_image.jpg" /> <br/> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fermentum  vestibulum nisl vitae placerat. Praesent nec massa neque. Nam dictum commodo posuere. Sed vitae est risus. Nunc suscipit justo vitae mi faucibus cursus. Morbi eu arcu erat. Nam venenatis, urna non tempus pretium, felis nunc blandit risus, non elementum elit turpis in diam. Proin ullamcorper blandit lacinia. Nulla nibh metus, lacinia at luctus vel, tincidunt et mauris. Sed rutrum, felis in tincidunt porttitor, nulla nunc placerat elit, ac tempor magna arcu non nisi. Proin ac sagittis lorem. Morbi imperdiet consectetur ipsum, volutpat convallis arcu pulvinar in. Nulla eget quam elit, vitae molestie ligula. Praesent rhoncus diam id lorem sagittis consequat ac et magna. </p> <hr> </div> </div> </div> <div id="left_col"> <div id="description"> <h1>Jose Argudo's Blog!</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean fermentum vestibulum nisl vitae placerat. Praesent nec massa neque. Nam dictum commodo posuere. Sed vitae est risus. Nunc suscipit justo vitae mi faucibus cursus. Morbi eu arcu erat. Nam venenatis, urna non tempus pretium, felis nunc blandit risus, non elementum elit turpis in diam. </p> </div> <div class="banner"> <img src="codeigniter_book.gif" /> &nbsp;&nbsp; Check my Codeigniter book </div> </div> <div id="footer"> <div id="left_footer"> Jose Argudo´s Blog </div> <div id="right_footer"> <img src="arrow.gif" /> </div> </div> </div> </body></html> We have our basic html structure here, quite simple by now, all html without any styling as of now. Our next step will be to add some css to our basic page, which, by now, looks more or less this way: Some reset css will be useful here, I usually use Eric Meyer's one, which you can find here: http://meyerweb.com/eric/tools/css/reset/ We are going to place this code in the head section of our page, just like this: ... <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/> <style type="text/css" media="screen"> /* CSS reset from Eric Meyer */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; outline: 0; font-size: 100%; vertical-align: baseline; background: transparent; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } :focus { outline: 0; } ins { text-decoration: none; } del { text-decoration: line-through; } table { border-collapse: collapse; border-spacing: 0; } </style> We have included this css styles in our html file, instead of including it from an external source. Why have we done that? Mostly because we have no ftp access to our Tumblr account, also themes are not packed in a zip file and installed somehow. Soon we will be answering all these questions; for now, placing our css styles directly in our html is the best solution. Now that we have added our reset styles, we can start working in the theme own styles, let's see: /* Theme's own styles */ #theme{ font-family: arial, sans-serif; font-size: 12px; color: #333333; background-color: #F5F5F5; } #container{ width: 960px; margin: 20px auto; } #menu{ height: 22px; } #left_col{ float: left; width: 320px; } #right_col{ float: right; width: 630px; } #footer{ float: none; clear: both; height: 20px; } #description, .banner{ background-color: #0087C5; padding: 12px; color: #ffffff; margin-bottom: 5px; } #description h1{ font-size: 24px; margin-bottom: 15px; } #description p{ line-height: 18px; } .banner{ font-style: italic; font-size: 10px; } .post_type{ width: 54px; float: left; margin-left: 10px; } .date{ width: 54px; float: left; color: #0087C5; font-style: italic; font-size: 10px; } .post_contents{ margin-left: 10px; margin-bottom: 22px; width: 500px; float: right; } .blue_box{ height: 54px; background-color: #0087C5; color: #ffffff; font-size: 14px; padding: 6px; padding-bottom: 0px; margin-bottom: 10px; } .post_contents h1{ font-size: 18px; color: #0087C5; margin-bottom: 22px; } .post_contents img{ margin-bottom: 24px; } .post_contents p{ line-height: 18px; } hr{ height: 1px; color: #0087C5; border: 1px solid #0087C5; } a.content_link:link, a.content_link:visited{ color: #0087C5; font-style: italic; font-size: 10px; text-decoration: none; } a.content_link:hover{ text-decoration: underline; } #menu{ color: #0087C5; } a.menu_link:link, a.menu_link:visited, a:link, a:visited{ color: #0087C5; font-size: 12px; text-decoration: none; } a.menu_link:hover, a:hover{ text-decoration: underline; } #left_footer{ width: 332px; height: 20px; float: left; background-color: #0087C5; color: #ffffff; } #right_footer{ width: 43px; float: right; } .padd{ padding: 4px; } .clear{ clear: both; float: none; } With these styles our template will be looking very similar to our design, maybe later we will need some small changes, but that's not so important. With all this in place, we can start with the interesting work, the Tumblr part. Generating the Tumblr theme from our template Converting this template into a working Tumblr theme is not going to be that hard, mostly we will be using some special tags to determine where some specific contents will be placed. Tumblr uses two type of tags Variable tags Block tags But we will see that better by working with our theme, for example, our page title: <title>Our first theme</title> We will change that for this code: <title>{Title}</title> In bold, we can see a {Title} tag. This tag, when rendered will be substituted by the title of our blog, without any html tag. Easy, isn't it? Most of our work will be quite similar, we are going to see the main tags to use. One of our main work will be showing the posts, after all, our main objective is to show these posts. Tumblr divides posts into eight possible types: Text posts, with only text and html. Photo posts, with one photo and its description Photosets, for when you need to show more than one photo Quote, used when we want to quote other site or source Link to other sites or online resources Chat, interesting option, for showing conversation, where each line, separated be a carriage return, is show in a different color. Audio, from an uploaded or external source Video, similar to audio but with videos. In our html code, we have prepared a zone for showing posts: <div class="post"> <div class="date"> <div class="blue_box">Mar 22</div> Posted at 7:54am </div> <div class="post_type"> <div class="blue_box">Text</div> <a href="#" class="content_link">Permalink</a> </div> <div class="post_contents"> . . . <hr> </div> </div> <br class="clear" /><br/> Now we need to generate one of these post zone for each post type. It's important to note that this is absolutely necessary for the theme to be correct, all post type must be present in our code. Firstly, we need to define these tags: {block:Posts} … {/block:Posts} All the other types of posts will go into these tags, let's summarize it a bit: {block:Posts} {block:Text} Text posts will go inside these tags {/block:Text} {block:Photo} Photo posts will go inside these tags {/block:Photo} {block:Photoset} Photoset posts will go inside these tags {/block:Photoset} {block:Quote} Quote posts will go inside these tags {/block:Quote} {block:Link} Link posts will go inside these tags {/block:Link} {block:Chat} Chat posts will go inside these tags {/block:Chat} {block:Audio} Audio posts will go inside these tags {/block:Audio} {block:Video} Video posts will go inside these tags {/block:Video} {/block:Posts} Now, we will be working on each one of these blocks. Remember that we will be placing them between {block:Posts} … {/block:Posts}, so we will have more or less this code: <div id="right_col"> {block:Posts} All the other block types will go here {/block:Posts}</div> Text Posts We will start with this type of posts, I will put the code and after we take a look at the different options {block:Text} <div class="post"> <div class="date"> {block:Date} {block:NewDayDate} <div class="blue_box">{Month} {DayOfMonth}</div> Posted at {12Hour}{AmPm} {/block:NewDayDate} {block:SameDayDate} <div class="blue_box">{Month} {DayOfMonth}</div> Posted at {12Hour}{AmPm} {/block:SameDayDate} {/block:Date} </div> <div class="post_type"> <div class="blue_box">Text</div> <a href="{Permalink}" class="content_link">Permalink</a> </div> <div class="post_contents"> {block:Title} <h1>{Title}</h1> {/block:Title} <p> {Body} </p> <hr> </div> </div> <br class="clear" /><br/> {/block:Text} Here we have some interesting tags, let's talk a bit about them: {block:Date} — this will render the date, with the options we are defining inside. {block:NewDayDate} — this is used for showing the date, but it's only show for the first post of the day. {block:SameDayDate} — If we want to show the date in each post, we need to use this tag. {Month} — with this tag we will show the day of the post {DayOfMonth} — and with this other we will show the day {12Hour} — the hour in a 12 hour format {AmPm} — and the am or pm text, where applicable {Permalink} — we used this inside our link href in order to generate a permalink {block:Title} — the code inside these tags will only be shown if the article has a title. {Title} — this is the title of the post. {Body} — and the content of the same. Most of the options are in fact very self explanatory, and quite easy to use. The next blog types are similar, but with some differences. Photo Posts The code for photo posts is quite similar, let's take a look to it: {block:Photo} <div class="post"> //same as before <div class="post_contents"> <img src="{PhotoURL-500}" alt="{PhotoAlt}"/> <p> {block:Caption}{Caption}{/block:Caption} </p> <hr> </div> </div> <br class="clear" /><br/>{/block:Photo} As you can see, we have changed the title tag for caption tag, but the structure remains mostly the same. The other main difference is the img tag we have used: <img src="{PhotoURL-500}" alt="{PhotoAlt}"/> The {PhotoAlt} tag will show the alt attribute of the photo, if there's any. {PhotoURL-500} is the more important one, as it will create the url of the image, but for a photo equal or smaller to 500px width. There are other options for this tag, which are as follows: {PhotoURL-400} — just the same tag, but will create a url for a image equal or smaller to 400px. {PhotoURL-250} — a smaller image, this time of 250px. {PhotoURL-100} — just the same as before, but will make urls for images of 100px width or less. {PhotoURL-75sq} — this one is a bit different, as will make a url for a reduced, squared image of the post, of 75px. {PhotoURL-HighRes} — this last tag will create a url for the high resolution image.
Read more
  • 0
  • 0
  • 2604
Visually different images

article-image-users-roles-and-pages-dotnetnuke-5
Packt
14 Apr 2010
7 min read
Save for later

Users, Roles, and Pages in DotNetNuke 5

Packt
14 Apr 2010
7 min read
One of the most important aspects of running a DotNetNuke portal is trying to figure out how to administer the portal. From adding modules to working with users, it may take a while before you have mastered all the administration tasks associated with running a portal. DotNetNuke uses a few terms that may be unfamiliar at first. For example, the term "portal" can be used interchangeably with the more common term "site". Similarly, the terms "tab" and "page" may be used interchangeably within the context of DotNetNuke. Knowing that they are interchangeable will help to understand the topics that we will discuss. User accounts If you are used to working within a network environment, or have worked with different portals in the past, then you are probably comfortable with the term "users". For those of us who may not be very familiar with this term, can think of a website that you have registered with in the past. When the registration had been completed, a user account was provided to you. This account lets you return to the site and log in as a recognized user. Everything that takes place on your portal revolves around users and user accounts. Whether users are required to register in order to use your services (such as a member site) or only a few user accounts are required to manage the content, functionality, and layout of your site, you will need to understand how to create and manage user accounts. Let's start with a general description of a user, and then you will see how to create and manage your users. In order to work through the examples, you will need to bring up your portal and sign in as an administrator account, such as the one created during the initial portal installation. Who is a user? The simplest definition of a user is an individual who consumes the services that your portal provides. However, a user can take on many different roles, from a visitor who is just browsing (unregistered user) or a person who registers to gain access to your services (registered user), to a specialized member of the site such as a content editor, to the facilitator (administrator or host) who is responsible for the content, functionality, and design of your portal. The difference between an administrator account and a host (or super user) account will be explained later in detail. For now, we will focus on the administrator account that is associated with a single portal. Everything in DotNetNuke revolves around the user, so before we can do anything else, we need to learn a little about user accounts. Creating user accounts Creating user accounts Before you create user accounts, you should decide and configure how users will be able to register on the site. You can choose from the following four different types of registrations: None Private Public (default) Verified To set the registration type for your portal, go to the Site Settings link found in the ADMIN menu, as shown in the following screenshot: The User Registration section can be found under Advanced Settings | Security Settings, as shown in the next screenshot: Many sections within DotNetNuke may be collapsed or hidden by default. To view these sections, you will need to expand them by clicking the '+' in front of them. The type of registration you use depends on how you will be using your portal. The following table gives a brief explanation of the different User Registration types: Registration setting Description None Setting the user registration as None will remove the Register link from your portal. In this mode, users can only be added by the administrator or host users. Thanks to the new features in DotNetNuke 5, users who have been given the proper permissions can also manage user accounts. This allows the administrator or host users to delegate account management to other individuals with the proper access. If you plan to have all sections of your site available to everyone (including unregistered users), then selecting None as your registration option is a good choice. Private If you select Private, then the Register link will reappear. After users fi ll out the registration form, they will be informed that their request for registration will be reviewed by the administrator. The administrator will decide whom to give access to the site. Unless an administrator approves (authorizes in DNN terms) a user, they will not be able to log in. Public Public is the default registration for a DotNetNuke portal. When this is selected, the users will be able to register for yoursite by entering the required information. Once the registration form is fi lled out, they will be given access to the site and can log in without requiring any action on the part of an administrator. Verified If you select Verified as your registration option, then the users will be sent an e-mail with a verifi cation code, once they fi ll out the required information. This ensures that the e-mail address they enter in the registration process is valid. The fi rst time they sign in, they will be prompted for the verifi cation code. Alternatively, they can click on the Verification link in the e-mail sent to them. After they have been verifi ed, they will need to type in only their login name and password to gain access to the site. Please note that proper SMTP confi guration is required to ensure delivery of the verifi cation e-mails. Setting required registration fields The administrator has the ability to decide what information the user will be required to enter when registering. If you are logged in as an administrator, then you can accomplish this through a combination of User Settings and Profile Properties. A user who is given the appropriate permissions can also modify these settings; however, this requires a few additional configuration steps that we will not cover in this section. To manage the Profile Properties for your site, select the ADMIN | User Accounts link. The User Accounts section appears as shown in the following screenshot: In the preceding screen, select Manage Profile Properties, either by selecting the link at the bottom of the module container or by selecting the link in the Action menu—the menu that pops up when you point on the drop-down button adjacent to the module title, User Accounts (more information on Action menu is provided later). When you select this link, you will be redirected to a screen (see the next screenshot) that displays a list of the currently configured Profile Properties. You can manage some attributes of the Profile Properties from within this screen. For instance, you can delete a property by clicking on the 'X' icon in the second column. Alternatively, you can change the display order of the properties by clicking on one of the Dn or Up icons in the third and fourth columns. If you change the order this way, make sure you click the Apply Changes button at the bottom of the page to save any changes. Your changes will be lost if you leave this screen without clicking the Apply Changes button. If you want even more control, then you can edit a single property by clicking on the pencil icon in the first column. You will see this icon extensively in the DNN user interface. It allows you to Edit/Modify the item it is associated with. You can also add a new property by selecting the Add New Profile Property action from the Action menu. In either case, you will be redirected to another page, where you can enter information about the property. You will be redirected to the Add New Property Details page, as shown in the following screenshot: Note that if you are editing an existing property, the Property Name field cannot be changed, so make sure you get it right the first time. If you need to change the Property Name, then you will need to delete and recreate the property. Most of these fields are self explanatory, but we will describe a few of these fields.
Read more
  • 0
  • 0
  • 1490

article-image-users-roles-and-pages-dotnetnuke-5-extension
Packt
14 Apr 2010
8 min read
Save for later

Users, Roles, and Pages in DotNetNuke 5- An Extension

Packt
14 Apr 2010
8 min read
Understanding DotNetNuke roles and role groups We just discussed how to add a user to your site. But are all users created equal? To understand how users are allowed to interact with the portal, we will need to take a look at what a role is and how it factors into the portal. There are plenty of real-world examples of roles we can look at. A police station, for example, can have sergeants, patrol cops, and detectives, and with each position come different responsibilities and privileges. In a police station, there are multiple people filling those positions (roles) with each of those belonging to the same position (role) sharing the same set of responsibilities and privileges. Roles in our portal work the same way. Roles are set up to divide the responsibilities needed to run your portal, as well as to provide different content to different groups of users of your portal. We want our portal to be easy for the administrators to manage. To do this, we will need to settle on the different user roles needed for our site. To determine this, we first need to decide on the different types of users who will access the portal. We will detail these user types in the following list: Administrator: The administrators will have very high security. They will be able to modify, delete, or move anything on the site. They will be able to add and delete users and control all security settings. (This role comes built-in with DotNetNuke.) The default administrator account is created during the creation of the portal. Home Page Admin: The home page admins will have the ability to modify only the information on the home page. They will be responsible for changing what users see when they first access your site. (We will be adding this role.) Forum Admin: The forum moderators will have the ability to monitor and modify posts in your forum. They will have the ability to approve or disapprove messages posted. (We will be adding this role.) Registered User: The registered users will be able to post messages in the forum and be able to access sections of the site set aside for registered users only. (This role comes built into DotNetNuke; however, we would need to provide the proper permissions to this role to perform the mentioned tasks.) Unauthenticated User: The unauthenticated user is the most basic of all the user types. Any person browsing your site will fall under this category, until they have successfully logged in to the site. This user type will be able to browse certain sections of your portal, but will be restricted from posting in the forum and will not be allowed in the Registered Users Only section. (This role comes built into DotNetNuke; however, we would need to provide the proper permissions to this role to perform the mentioned tasks.) Once you formulate the different user roles that will access the site, you will need to re strict users' access. For example, we only want the Home Page Admin to be able to edit items on the home page. To accomplish this, DotNetNuke uses role-based security. Role-based security allows you to give access to portions of your website based on what role the user belongs to. User-based security is also available per page or content section of the portal. However, the benefit of using a role-based security method is that you only have to define the access privileges for a role once. Then you just need to add users to that role and they will possess the privileges that the role defines. The following diagram gives you an idea of how this works: Looking at the diagram, we notice two things: Users can be assigned to more than one role More than one user can be assigned to a single role This gives us great flexibility when deciding on the authorization that users will possess in our portal. To create the roles we have detailed, sign in with an administrator account, and select ADMIN | Security Roles on the main menu or click the Roles link in the Common Tasks section of the control panel. This is available on the top of every DNN page for authorized users. You might need to click the double down arrows on the top-right of the page to maximize the panel. The Security Roles page appears as shown in the following screenshot: Notice that DotNetNuke comes with three roles already built into the system: the Administrators role (which we have been using), the Registered Users role, and the Subscribers role. Before we jump right into creating the role, let us first discuss the role group feature of DotNetNuke, as we will be using this feature when we create our roles. A role group is a collection of roles used, mainly, in large sites with a large number of roles, as a way of managing the roles more effectively. For the site we are building, the benefit of using role groups will be minimal. However, in order to demonstrate how to use them, we will create one for our administrative roles. While on the Security Roles page, click the Add New Role Group link located below the list of roles. This will present us with the Edit Role Group page containing two form fields. Once these fields are filled out, click the Update link at the bottom of this page. A Filer By Role Group drop-down list should now be displayed above the list of roles on the Security Roles page. If you select the Administrative Roles group that we just created, two noticeable things happen on this page. Firstly, the list of roles become empty as no roles are currently assigned to this role group. Secondly, an edit (pencil) icon and a delete (red cross X) icon now appear next to the drop-down list. These icons can be used to update or remove any custom role groups that exist on the site. These red 'X' icons are standard icons used throughout DotNetNuke to represent the ability to delete/remove items. Now that we have created our role group, we want to create the role for Home Page Admin. To do this, you again have two choices. Either select Add New Role from the dropdown in the upper left, or click on the Add New Role link. This will bring up the Edit Security Roles page, as shown in the next screenshot. We will use this page to create the Home Page Admin role that we need. The Basic Settings shown in the screenshot are as follows: Role Name: Make the name of your role short, but descriptive. The name should attempt to convey its purpose. Description: Here you may detail the responsibilities of the role. Role Group: Set this field to the Administrative Roles group that we created earlier. Public Role: Checking this will give registered users of your site the ability to sign up for this role themselves. We will be creating a Newsletter role and will demonstrate how this works when it is created. Auto Assignment: If this is checked, users will automatically be assigned to this role as soon as they register for your portal. CAUTION Do not check the Public Role and Auto Assignment checkboxes, unless you are sure. Checking these options would allow all users of the site to become members of the associated role, which would grant them the privileges assigned to the role. As we want to decide who will be able to modify our home page, we will leave both of these unchecked. To save the settings, click on the Update link. The Advanced Settings section allows you to set up a fee for certain security roles. We will not be configuring any of these settings for this particular exercise. However, we will briefly discuss how these settings can be used in Assigning security roles to users section. Now to complete the roles that we will require for Coffee Connections, we will add two more security roles The first role will be called Newsletter. We will be using this role to allow users to sign up for the newsletter we will be hosting at the Coffee Connections site. Set up the security role with the following information: Role Name: Newsletter Description: Allows users to register for the Coffee Connections Newsletter Role Group: Leave this as the default < Global Roles > as it is not going to be used to grant administrative rights to its members Public Role: Yes (checked) Auto Assignment: No (unchecked) Click on the Update link to save this role. The second role will be called Forum Admin. We will be using this role to administer the forums at the Coffee Connections site. Set up the security role with the following information: Role Name: Forum Admin Description: Allows user to administer Coffee Connections Forum Role Group: Administrative Roles Public Role: No (unchecked) Auto Assignment: No (unchecked)
Read more
  • 0
  • 1
  • 3881

article-image-programming-php-nuke
Packt
13 Apr 2010
27 min read
Save for later

Programming PHP-Nuke

Packt
13 Apr 2010
27 min read
After a quick look at the file and folder structure of a module, we then begin creating a new module for PHP-Nuke. This module will allow items of content to be submitted for modules that do not support user-submitted content. In this article, we will code functionality for users to submit encyclopedia entries for administrator approval. However, this will not involve making any modifications to the Encyclopedia module, and can be extended to cover other modules as well. What Happens When a Page is Requested? Let's see what happens when a visitor wants to view an article on the site, and the process that PHP-Nuke goes through to construct the page containing this information. Viewing an article means that the visitor will be navigating to a page similar to this: http://localhost/nuke/modules.php?name=News&file=article&sid=1 The page requested by the visitor is modules.php, so let's have a look at that. Note that although there are many PHP files in the PHP-Nuke installation, there are only four files actually requested in the normal course of interaction with the site: index.php modules.php admin.php backend.php The other files in the PHP-Nuke installation are used by these files when required. Where Does PHP-Nuke Get Information From? PHP-Nuke is able to collect information about what module the visitor wants to see, what operation they want to perform, and details of the user from request variables coming from these places: The query string in the URL: The URL of the page holds information that tells PHP-Nuke which module to select, which part of the module to use, what item of content to show, and so on. The query string information is used to select the page from the system that needs to be shown to the visitor. Posted variables: When a user enters information in a form, and submits this back to the server, this information will be available to PHP-Nuke. This posted information is how PHP-Nuke gets input from the user to create items of content, enter terms to search for, and so on. Cookie variables: There is user account information stored in a cookie (and administrator account information if the user has such an account). This is used to identify the user, so they do not have to keep logging on every time they view a page or come to the site. When the user logs out, this information is deleted from the cookie. The information that PHP-Nuke gets from these sources has to be treated very carefully within the system. These sources are the only means through which visitors communicate with the site, and are also the channels through which hacks or attacks might be conducted on the site. The patches we applied in Article 2 while installing the system address precisely this issue, and they make sure that the data PHP-Nuke collects from a visitor is in exactly the right form for working with. Requesting a Page Once the modules.php page is requested, the first step followed is to include the mainfile.php file. This file does the following things: It checks and processes the request variables (namely the input to the application), to avoid possibly harmful tags, or other indicators of some form of SQL injection attack. It creates global variables for each request variable. It sets up a connection to the database. It gets the site configuration such as the site name, site logo, and so on, from the database. The mainfile.php file also contains a number of core functions such as checking if the user is logged in or is an administrator, choosing the blocks to display, and filtering text, among others. These will be used at different points in the creation of the page. After this file has been included, the next thing to happen in modules.php is that PHP-Nuke gets the requested module from the $name global variable, which corresponds to the name query string variable (as in modules.php?name=News), and checks if this module is active. If the module isn't active, and the visitor isn't an administrator, a 'Module Not Active' message is displayed, and the page output is done. If the module is active, then PHP-Nuke checks if the visitor has rights to access this module. PHP-Nuke checks to see if the access is restricted to a particular user group, and if so, is the user a member of that group? PHP-Nuke also checks if the module is for subscribers only, and if so, is the user a subscriber to the site? If the visitor doesn't have the right permissions to view the module, then a 'No Access' message is displayed, and the page output is done. If the module selected by the visitor is active, and they do have permission to view it, then PHP-Nuke can get on with passing control to that module. Control is passed to the selected module by attempting to include the index.php file in the folder of the selected module. However, if there is a file variable in the query string, then the file with that name is included instead. If these files can't be found, a 'Module Cannot Be Found' error is displayed to the visitor. Thus if the user requests a page like modules.php?name=News&file=article&sid=1, the article.php file in the News folder will be included by PHP-Nuke. If the user requests a page like modules.php?name=News&sid=1, then the index.php file in the News folder will be included. Attempting to request a page like modules.php?name=News&file=nosuchfile returns a page with a 'No such page' message, since there is no file called nosuchfile.php in the News folder. The 'No such page' message is generated by PHP-Nuke, since it's in control of the process. If the user has selected an active module for which they have view permission, and are requesting a page that is part of the module, then control passes to the module, and it's up to that module to do its work and create the page. We'll see how this works later in the article, but for now, our overview of how PHP-Nuke gets the page creation underway is complete. Seeing how PHP-Nuke works isn't particularly exciting, what is more exciting is seeing how we can extend the power of PHP-Nuke by creating new blocks and modules. Along the way, we'll see most of the components required for 'programming' with PHP-Nuke, and you'll get a good idea of how to go about your own development projects. Creating a Block Our development efforts begin with creating a File block. A File block is a PHP script that is stored in the blocks folder. It must have a filename of the form block-NAME.php, where NAME will be used by PHP-Nuke as the title for the block. The filename should not contain any spaces. The goal of a block is simple. It just has to create one variable, $content, that holds the content of the block. After that, the PHP-Nuke core will bring the theme into play to take care of displaying the block. The block we will create is a better version of the Dinosaur of the Day static HTML block we created in Article 4. The block will display the name of the Dinosaur of the Day, and a thumbnail image of the lucky lizard. However, on the next day, a different dinosaur will be chosen, and the block display will be updated. This is how the block works: We will create a database table to hold the date, the title of the dinosaur for that day, and a link to the thumbnail image of that dinosaur. We will create a text data file that will contain the name of a dinosaur and a link to its thumbnail image on each line. The data in this file will be the dinosaur pool from which the dinosaur of the day is chosen at random. When the block code is executed, it will look in the database table to see if there is any information for the current date. If there is, it will retrieve it and build the block output. If there is no information for the current date, the data from the text file will be loaded in. One of the entries in that file will be selected at random, and that data will be inserted into the database. This will become the Dinosaur of the Day. That data will then be used to create the block output. We will use the text file to hold the 'Dinosaur of the Day' candidates rather than a database table so that we do not have to create a separate administration feature to add these details. To add more dinosaurs to the list, we simply upload a new version of the text file. Make sure that you copy the dinosaur thumbnails from the code download into the imagesdinosaurstnails folder of your PHP-Nuke installation root. Time For Action—Creating the Database Table Open up phpMyAdmin in your web browser, and select the nuke database from the drop-down list in the left-hand panel. Click on the SQL tab, and enter the following code into the textbox, then click on Go. CREATE TABLE dinop_dinoportal_dotd (id INT( 10 ) NOT NULL AUTO_INCREMENT ,day VARCHAR( 16 ) NOT NULL ,title VARCHAR( 128 ) NOT NULL ,image VARCHAR( 250 ) NOT NULL ,PRIMARY KEY ( 'id' )) TYPE = MYISAM ; What Just Happened? We just created our database table. There is only one table needed, with a simple design. There are four fields in the table. The id field will hold an auto-incrementing unique numerical value and the other fields will hold the current date, the title of the dinosaur, and the link to the image of the dinosaur. Time For Action—Creating the Text File Open up your text editor, and enter the following: Tyrannosaurus Rex,images/dinosaurs/tnails/tyro.gifStegosaurus,images/dinosaurs/tnails/stego.gifTriceratops,images/dinosaurs/tnails/triceratops.gif Save this file as dotd_list.txt in the blocks folder. What Just Happened? The dotd_list.txt file will be the data source for choosing a new Dinosaur of the Day image. You will notice that we are storing the data here in the form 'name of the dinosaur', 'path to the image', so it will be easy to extract the information when we need it. Time For Action—Creating the Block Code Open up your text editor, and enter the following code into a blank file: <?phpif ( !defined('BLOCK_FILE') ){ Header("Location: ../index.php"); die();}global $prefix, $db;$today = date('d-m-Y');$sql = "SELECT * from ".$prefix."_dinoportal_dotd WHERE day='$today'";$result = $db->sql_query($sql);$content = "";$dino_title = "";$image = ""; $numrows = $db->sql_numrows($result); if ($numrows) { $row = $db->sql_fetchrow($result); $dino_title = $row['title']; $image = $row['image']; } else { $filename = "blocks/dotd_list.txt"; $possibles =@ file($filename); if ($possibles) { $choice = rand(1, count($possibles)); $imp = explode("," , $possibles[$choice-1]); $dino_title = $imp[0]; $image = $imp[1]; $sql = "INSERT INTO ".$prefix."_dinoportal_dotd(day,title,image) VALUES ('$today', '$dino_title', '$image')"; $result = $db->sql_query($sql); } $choice = rand(1, count($possibles)); $imp = explode("," , $possibles[$choice-1]); $dino_title = $imp[0]; $image = $imp[1]; }if ($dino_title){ $content = "Today's dinosaur is:<br><center><b>$dino_title</b><center><br>"; $content .= "<center><img src="$image" alt="$dino_title"></center><br>";}?> Save this file as block-DinosaurOfTheDay.php in the blocks folder of your PHP-Nuke installation. What Just Happened? We just entered the code for the Dinosaur of the Day block, and we'll step through it now. This first part of the code stops this file being requested directly by a visitor— the BLOCK_FILE constant is defined in mainfile.php, and without that constant being defined, the visitor would be redirected back to the homepage of the site. Block files are never requested directly by the visitor, they are included by PHP-Nuke. These first few lines of code are found in every block file: if ( !defined('BLOCK_FILE') ){ Header("Location: ../index.php"); die();} Now we can get started. First, we set ourselves to access some of the global variables of the application, and we will have our first look at the objects to access data from the database. The only global variables we need here are the ones for data access—$prefix, which holds the value of the database tables prefix, and $db, which is used to actually perform database operations. global $prefix, $db; Next, we grab today's date, formatted as digits like this 24-05-2005. $today = date('d-m-Y'); Now we set up the SQL statement to retrieve the information corresponding to this date from the database: $sql = "SELECT * from ".$prefix."_dinoportal_dotd WHERE day='$today'"; Now we execute the SQL statement: $result = $db->sql_query($sql); It is possible that there is no data corresponding to today's date, so we check the number of rows returned from this last query. If there are zero rows, there will be no information. $numrows = $db->sql_numrows($result); If there are some rows returned, we can start creating the block output. We use the sql_fetchrow() method to retrieve a row of data from the result of the query. This row is returned as an array, and we set some variables from the array. We'll only grab one row. If for some reason, there is more than one entry for today's date, we simply ignore the others. if ($numrows){ $row = $db->sql_fetchrow($result); $dino_title = $row['title']; $image = $row['image'];} Now we move on to the situation where there is no information for today's date, and we have to create it. The first thing we do is to read the contents of the dotd_list.txt file into an array—there will be one entry in the array for each line in the text file. However, we have to consider what will happen if there is some kind of problem reading the file. else{ $filename = "blocks/dotd_list.txt"; Note that the path to the file for the dodt_list.txt file is blocksdotd_list.txt. This may seem strange, since both this file and the block file are in the same blocks folder. However, PHP will be looking for this file from the executing script, which will be one of index.php, modules.php, or admin.php, all of which are outside the blocks folder. Thus we need to add the blocks folder in the path to the dotd_list.txt file. Now we try to grab the file itself: $possibles =@ file($filename); The file function opens the named file, and reads the input into an array called $possibles. The use of the @ character here will suppress any error messages—if there is a problem opening or reading the file, no untidy error messages will be displayed to the user, and execution can continue. Of course, if there is a problem reading the file then there will be a problem with $possibles. So we check this next—if there has been some problem reading the file then $possibles will be false: if ($possibles){ If there is something stored in $possibles, then this check will be passed, and we can proceed to choose one element from it at random. We choose a random number, between 1 and the number of lines in the text file. $choice = rand(1, count($possibles)); All we have to do now is choose that element from the array (we have to subtract one from the random number because the first element of the array is 0, rather than 1), and then split up that line to get at the title and the path to the image. $imp = explode("," , $possibles[$choice-1]);$dino_title = $imp[0];$image = $imp[1]; We split the line using the explode() function. The explode() function converts a string to an array by splitting it at certain characters. We will split the string at the ',' character, and we get an array with two entries. The first entry is the name of the dinosaur; the second is the path of the image. Now we have the details of our Dinosaur of the Day, we can add it to the database using an INSERT SQL statement. $sql = "INSERT INTO ".$prefix."_dinoportal_dotd(day,title,image) VALUES ('$today', '$dino_title', '$image')"; $result = $db->sql_query($sql); }} At this point, we should have a Dinosaur of the Day, one way or another, and so we can finalize the block output. However, we check the value of the $dino_title variable just in case there has been some problem either retrieving data or creating the new Dinosaur of the Day. If there has been a problem with either of these, there will be no value for the $dino_title variable, and if so, this code will ensure that the block content will remain empty, rather than producing some useless output. if ($dino_title){ $content = "Today's dinosaur is:<br><center><b>$dino_title</b><center><br>"; $content .= "<center><img src="$image" alt="$dino_title"></center><br>";} That's it, our block is complete! The key points of this block were the initial few lines that stopped the file from being requested directly, and this was also our first encounter with the data access code. Another thing to note from this example is the effort we made to ensure that the block output was only created if everything went smoothly. We suppressed errors when trying to read in a file, we checked that the reading of a file had actually given us some data, and then we didn't create any output if there was a problem with dino_title variable, which would be an indicator of some problem. All this means that if there is a problem, the visitor will not be confronted with lots of error messages, which could disturb the visitor and lead to a poor impression of your site, or even break the layout of the page, or reveal some information about your code that could be used against you. All that remains now is to set up this File block using the steps we saw in Article 4, and we are away! Data Access in PHP-Nuke In the code for creating the block we had a couple of lines with data access functions: $result = $db->sql_query($sql);$numrows = $db->sql_numrows($result);$row = $db->sql_fetchrow($result); PHP-Nuke uses a 'data abstraction layer', which means that you call functions against an object, which translates them into specific calls against the database of your choice. Generally, MySQL is the database used with PHP-Nuke, but you could choose another database server to power your site. A more pertinent advantage is that you don't need to use database-specific functions to access data in PHP-Nuke; you only need to learn about the functions of the data access object (You will still need to know some SQL to create queries that will be executed on the database). The code for the data access object is found in the file dbmysql.php. In fact, the db folder contains code for different types of database server, but this file is the one selected by default by PHP-Nuke for working with the MySQL database server. The data access object is a genuine object, that is, it's an instance of a class, sql_db in this case. Classes are one of the basics of object-oriented programming, but other than this instance PHP-Nuke does not make much use of object-oriented programming. A discussion of object-oriented programming in PHP is beyond the scope of this article series, and it won't particularly help here since PHP-Nuke makes so little use of it. All that we need to know is how to access the methods (functions) of the data access object. Object-oriented programming is covered in more detail in any book on PHP programming, and you can read an article about it at http://www.devarticles.com/c/a/PHP/Object-Oriented-Programming-in-PHP/. The data-access object provides a number of methods that you can use to execute a query, retrieve a row of data, check the number of rows returned by the query, or get the last inserted auto-increment field. Working with the object follows a similar process to the standard way of working with data in PHP using functions like mysql_query() or mysql_fetch_field(). To access data in PHP-Nuke, you will need two global variables, $prefix and $db. The $prefix variable holds the table prefix of the database tables, and this needs to be used in your SQL queries. The $db variable is the data access object itself. In our block example, we had these lines to create a SQL query and then execute it: $sql = "SELECT * from ".$prefix."_dinoportal_dotd WHERE day='$today'";$result = $db->sql_query($sql); Note the $db->sql_query() syntax. This syntax is used in PHP to call a method on an object, in this case the sql_query() method of the $db object. The sql_query() method executes an SQL query as its name suggests. You provide a string with the query that's to be executed as a parameter. Following the execution of a query, you can retrieve a row using the sql_fetchrow() method: $row = $db->sql_fetchrow($result); This method returns an array, and you can refer to the fields in the data using $row['fieldname'], as we do in the block example to get the title and image fields: $dino_title = $row['title'];$image = $row['image']; If you want to insert or update data, you need to create the relevant SQL query and then use the sql_query() function to do it: $sql = "INSERT INTO ".$prefix."_dinoportal_dotd(day,title,image) VALUES ('$today', '$dino_title', '$image')";$result = $db->sql_query($sql); This is only a small selection of the methods of the data access object. Another interesting one is the sql_nextid() method, which you can use after an INSERT statement to get the value of the last auto-increment field created. However, these are the methods that you will see the most of as you look around the code in PHP-Nuke. Module File and Folder Structure Before we get started creating a new module, let's have a look at the file structure of a typical module. A module is simply a collection of files (usually only PHP files) contained in a folder that goes in the modules folder in the root of the PHP-Nuke installation. The name of the folder is the name that PHP-Nuke will recognize the module by. However, we can't just place the files into the module folder in any order. There is an organization of files, subfolder names, and filenames that modules need to follow in order to function properly with PHP-Nuke. The image below shows the contents of the News module folder: We have already seen how PHP-Nuke switches between files in the module folder based on the value of the file query string variable. If there is no value for this variable, the index.php file of the module is used. Files that sit inside the module folder are the 'front-end' files, which will be used during a standard user's visit to the module. The code for the administration part of a module resides in the admin folder within the module folder. In earlier versions of PHP-Nuke (before 7.5), the administration code for any module would have to go into the admin folder (the one in the root of the PHP-Nuke installation), and would be mixed with the 'core' administration code. The decision to have a module's administration code contained within the module folder itself means that the module is much more self-contained, keeps people away from the core code itself, and generally makes the module easier to set up, install, and maintain. We'll see more about what is found in the admin folder when we create the administration area of our new module later in this article. We saw in Article 4 that the Language block allows you to change PHP-Nuke's user interface language. This ability to switch languages is something that has made PHP-Nuke so popular all around the world. This multi-language support is achieved by module developers avoiding coding any 'localizable' text into the module output. Localizable text is text that needs to be translated if a different interface language is selected. Instead of coding the text, PHP constants are used, with the values of the constants defined in a language file. The language files are found in the language folder of the module, and there is a separate language file for each language, each with a filename of the form lang-LANGUAGE.php. All PHP-Nuke needs to do is select the correct file based on the desired language. Creating a User Submissions Module Writing a new module allows you to extend PHP-Nuke to get it to do exactly what you want it to do. What we will do here is to create a general-purpose module that will allow users to submit content for modules that do not support user-submitted material. We'll call it UserSubmissions. It will work in the way the Submit News module works for stories: The user will submit the material through a form. The administrator will be notified of the new submission by email. The administrator will be able to see a list of the submitted material in the administration area, and can edit, delete, or approve the material to go into the database. The point of this module is that it does not touch the modules for which it allows the submission of content; everything will happen in the UserSubmissions module. In this article, we will only code in functionality for users to submit encyclopedia entries. It is straightforward to extend this to allow submissions for the Content module, or questions for the FAQ module. Conceptually what the module does is to: Present a form to the user similar to the one the administrator would use for entering an encyclopedia entry. Take the user's input and store it in a 'general' way in a single database table. After the administrator checks the input, the data is then stored in the encyclopedia's database tables using the same kind of code that the Encyclopedia module uses. We will see exactly what the 'general' way we store the data in is later. Basically, the module will take all the parts of the encyclopedia entry—the title, the text, the encyclopedia ID—and put them all together into one bundle, which can then be easily retrieved and broken out to form the individual pieces of data for the administrator to view, approve, or delete. Rather than presenting the development as a series of steps for you to follow, we will break the code up into various tasks, and then examine each piece of code or activity. You can type in the code as it is presented, although it is probably easiest to grab the example code for this module from the code download, and refer to it as we go. Module Development Steps The steps that we will follow to create the module are these: Create the module folder Create the database tables Code the front end (visitor view) of the module Adapt the code for multi-language support Set up module administration Code the administration area Rather unusually, we're going to start by coding the front end of the site. The reason this is unusual is that modules typically display some kind of data (that is what all the modules we have encountered in the article series do), and you would first need to enter this data into the database. This data is usually entered by the administrator, through the administration interface. With some example data in place, the front end of the site will be able to display it. It will be difficult to test the front end if it is supposed to display data and there is no data to display! This module does not require any existing data in the database to work. In fact, the data is entered by a standard visitor, and the administrator only has to look at this data, and edit or delete it. There is no facility in the administrator part of the module for the administrator to add new data into the module, which would rather defeat the point of this module! Thus we can start on the front end of the module quite happily. Let's start off with creating the module folder. Creating the Module Folder Create a new folder in the modules folder called UserSubmissions. This will be our module folder. Within this folder, create two new folders called admin and language. The admin folder will contain our administration code, and the language folder will contain the user interface language files. We create another folder, inside the admin folder, also called language. This folder will hold the language files for the module's administration interface. That's the first step out of the way, so let's move on to the database tables. Creating the Database Tables The module has only one database table. The table will be called <prefix>_usersubmissions. You can follow the same steps in phpMyAdmin as we did earlier for creating the block database table to create this table: CREATE TABLE dinop_usersubmissions ( id int(11) NOT NULL auto_increment, data text NOT NULL, parent_id int(11) NOT NULL default '0', type varchar(36) NOT NULL default '1', user_id int(11) NOT NULL default '0', date timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, title varchar(255) NOT NULL default '', user_name varchar(250) NOT NULL default '', PRIMARY KEY (id)) COMMENT='Table for holding user submitted content' ; Each row in this table will represent a single item of submitted content. The row will be identified by its id field. With only one table, you may be wondering how this module is going to be able to hold data from different modules. The answer is that the submitted data will be bundled up into a single object, then 'serialized' and stored in the data field. When the data is needed for viewing, it will be unbundled, and 'unserialized' back into a form that can be worked with. The 'title' of the submission will be stored in the title field. The type of module that we are storing data for will be held in the type field of the row. The details of the submitter will be stored in the user_id and user_name fields. We actually only use the user_name field in this version of the module, but we store both for future use. The date the item is submitted is held in the field called date. This field is a MySQL TIMESTAMP, and whenever a row is inserted, the current date and time will be inserted into the field automatically by the database, so we will not need to record the date and time ourselves. The final field is parent_id. Recall how an encyclopedia entry belongs to an Encyclopedia; a content page belongs to a Content category; a FAQ question belongs to a particular category, and so on. For each of these types of content, you needed to provide a 'parent' object that the content would belong to. That is where our parent_id field comes in. The ID of the parent object will be stored in this field. For an encyclopedia entry, this will be the ID of the chosen Encyclopedia.
Read more
  • 0
  • 0
  • 2045
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 €14.99/month. Cancel anytime
article-image-understanding-dotnetnuke-core-architecture
Packt
06 Apr 2010
13 min read
Save for later

Understanding the DotNetNuke Core Architecture

Packt
06 Apr 2010
13 min read
Architecture overview As opposed to traditional web applications that may rely on a multitude of web pages to deliver content, DotNetNuke uses a single main page called Default.aspx. The content for this page is generated dynamically by using a tabID value to retrieve the skin and modules needed to build the page requested, from the DotNetNuke database. Before we move on, we should discuss what is meant by a tab and a page. As you read this article, you will notice the word "tab" is sometimes used when referring to pages in your DotNetNuke portal. In the original IBuySpy application, pages were referred to as tabs because they resembled tabs when added to the page. IBuySpy application, the skeleton ASP.NET Framework, was created by Microsoft to demonstrate ASP.NET features, and DotNetNuke was originally derived from it. This continued in the original versions of the DotNetNuke project. Starting with version 3.0, and continuing with version 5.2.x, there has been an ongoing effort to rename most of these instances to reflect what they really are: pages. Most references to "tabs" have been changed to "pages", but the conversion is not complete. For this reason, you will see both—tabs and pages—in the database, in the project files, and in this text. We will use these terms interchangeably throughout this text as we look into the core architecture of DNN. We will begin with a general overview of what happens when a user requests a page on your DotNetNuke portal. The process for rendering a page in DotNetNuke works like this: a user navigates to a page on your portal; this calls the Default.aspx page, passing the tabid parameter in the querystring to let the application identify the page being requested. The example http://www.dotnetnuke.com/Default. aspx?tabid=476 demonstrates this. DotNetNuke 3.2 introduced something called URL rewriting. This takes the querystring shown above and rewrites it so that it is in a format that helps increase search engine hits. We will cover the HTTP module that is responsible for this in more detail later in this article. The rewritten URL would resemble http://localhost/DotNetNuke/Home.aspx. This assumes that the page name for tabid 476 is Home. While referring to URLs in this article we will be using the non-rewritten version of the URL. URL rewriting can be turned off in the friendly URL section of the Host Settings page. The querystring value (?tabid=476) is sent to the database, where the information required for the page is retrieved, as shown in the following diagram: The portal that the user is accessing can be determined in a number of ways, but as you can see from the Tabs table (see the following screenshot), each page/tab contains a reference to the portal it belongs to in the PortalID field. Once the server has a reference to the page that the user requested (using the tabID), it can determine what modules belong to that page. Although there are many more tables involved in this process, you can see that these tables hold not only the page and modules needed to generate the page, but also what pane to place them on (PaneName) and what container skin to apply (ContainerSrc). All of this information is returned to the web server, and the Default.aspx page is constructed with it and returned to the user who requested it along with the required modules and skins, as shown in the following diagram. Now, this is of course a very general overview of the process, but as we work through this article, we will delve deeper into the code that makes this process work, and in the end, show a request work its way through the framework to deliver a page to a user. Diving into the core There are over 160,000 lines of code in the DotNetNuke application. There is no practical (or even possible) way to cover the entire code base. In this section, we will go in depth into what I believe are the main portions of the code base: the PortalSettings as well as the companion classes found in the portals folder; the web.config file including the HTTP Modules and Providers; and the Global.asax and Globals.vb files. We will start our discussion of the core with two objects that play an integral part in the construction of the architecture. The Context object and the PortalSettings class will both be referred to quite often in the code, and so it is important that you have a good understanding of what they do. Using the Context object in your application ASP .NET has taken intrinsic objects like the Request and the Application objects and wrapped them together with other relevant items into an intrinsic object called Context. The Context object (HttpContext) can be found in the System.Web namespace. In the following table, you will find some of the objects that make up the HttpContext object. Title Description Application Gets the HttpApplicationState object for the current HTTP request. Cache Gets the Cache object for the current HTTP request. Current Gets the HttpContext object for the current HTTP request. This is a static (shared in VB) property of the HttpContext class, through which you access all other instance properties discussed in this table, that together enable you to process and respond to an HTTP request. Items Gets a key-value collection that can be used to organize and share data between an IHttpModule and an IHttpHandler during an HTTP request. Request Gets the HttpRequest object for the current HTTP request. This is used to extract data submitted by the client, and information about the client itself (for example, IP ), and the current request. Response Gets the HttpResponse object for the current HTTP response. This is used to send data to the client together with other response-related information such as headers, cacheability, redirect information, and so on. Server Gets the HttpServerUtility object that provides methods used in processing web requests. Session Gets the HttpSessionState instance for the current HTTP request. User Gets or sets security information for the current HTTP request. Notice that most of the descriptions talk about the "current" request object, or the "current" response object. The Global.asax file, which we will look at soon, reacts on every single request made to your application, and so it is only concerned with whoever is "currently" accessing a resource. The HttpContext object contains all HTTP-specific information about an individual HTTP request. In particular, the HttpContext.Current property can give you the context for the current request from anywhere in the application domain. The DotNetNuke core relies on the HttpContext.Current property to hold everything from the application name to the portal settings and through this makes it available to you. The PortalSettings class The portal settings play a major role in the dynamic generation of your pages and as such will be referred to quite often in the other portions of the code. The portal settings are represented by the PortalSettings class which you will find in the EntitiesPortalPortalSettings.vb file. As you can see from the private variables in this class, most of what goes on in your portal will at some point needto access this object. This object will hold everything from the ID of the portal to the default language, and as we will see later, is responsible for determining the skins and modules needed for each page. Private _PortalId As IntegerPrivate _PortalName As StringPrivate _HomeDirectory As StringPrivate _LogoFile As StringPrivate _FooterText As StringPrivate _ExpiryDate As DatePrivate _UserRegistration As IntegerPrivate _BannerAdvertising As IntegerPrivate _Currency As StringPrivate _AdministratorId As IntegerPrivate _Email As StringPrivate _HostFee As SinglePrivate _HostSpace As IntegerPrivate _PageQuota As IntegerPrivate _UserQuota As IntegerPrivate _AdministratorRoleId As IntegerPrivate _AdministratorRoleName As StringPrivate _RegisteredRoleId As IntegerPrivate _RegisteredRoleName As StringPrivate _Description As StringPrivate _KeyWords As StringPrivate _BackgroundFile As StringPrivate _GUID As GuidPrivate _SiteLogHistory As IntegerPrivate _AdminTabId As IntegerPrivate _SuperTabId As IntegerPrivate _SplashTabId As IntegerPrivate _HomeTabId As IntegerPrivate _LoginTabId As IntegerPrivate _UserTabId As IntegerPrivate _DefaultLanguage As StringPrivate _TimeZoneOffset As IntegerPrivate _Version As StringPrivate _ActiveTab As TabInfoPrivate _PortalAlias As PortalAliasInfoPrivate _AdminContainer As SkinInfoPrivate _AdminSkin As SkinInfoPrivate _PortalContainer As SkinInfoPrivate _PortalSkin As SkinInfoPrivate _Users As IntegerPrivate _Pages As Integer The PortalSettings class itself is simple. It is filled by using one of the constructors that accepts one or more parameters. These constructors then call the private GetPortalSettings method . The method is passed a tabID and a PortalInfo object. You already know that the tabID represents the ID of the page being requested, but the PortalInfo object is something new. This class can be found in the same folder as the PortalSettings class and contains the basic information about a portal such as PortalID, PortalName, and Description. However, from the PortalSettings object, we can retrieve all the information associated with the portal. If you look at the code inside the constructors, you will see that the PortalController object is used to retrieve the PortalInfo object. The PortalInfo object is saved in cache for the time that is specifi ed on the Host Settings page. A drop-down box on the Host Settings page (DesktopModulesAdminHostSettingsHostSettings.ascx) is used to set the cache. No caching:0 Light caching:1 Moderate caching:3 Heavy caching:6 The value in this dropdown ranges from 0 to 6; the code in the DataCache object takes the value set in the drop-down and multiplies it by 20 to determine the cache duration. Once the cache time is set, the method checks if the PortalSettings object already resides there. Retrieving these settings from the database for every request would cause your site to run slowly, so placing them in a cache for the duration you select helps increase the speed of your site. Recent versions of DotNetNuke have focused heavily on providing an extensive caching service. An example of this can be seen in the following code: Dim cacheKey As String = String.Format(DataCache.PortalCacheKey,PortalId.ToString())Return CBO.GetCachedObject(Of PortalInfo)(New CacheItemArgs(cacheKey, DataCache.PortalCacheTimeOut,DataCache.PortalCachePriority, PortalId),AddressOf GetPortalCallback) We can see in the previous code that the CBO object is used to return an object from the cache. CBO is an object that is seen frequently throughout the DotNetNuke core. This object's primary function is to return the populated business object. This is done in several ways using different methods provided by CBO. Some methods are used to map data from an IDataReader to the properties of a business object. However, in this example, the Get CachedObject method handles the logic needed to determine if the object should be retrieved from the cache or from the database. If the object is not already cached, it will use the GetPortalCallback method passed to the method to retrieve the portal settings from the database. This method is located in the PortalController class (EntitiesPortalPortalController.vb) and is responsible for retrieving the portal information from the database. Dim portalID As Integer = DirectCast(cacheItemArgs.ParamList(0),Integer)Return CBO.FillObject(Of PortalInfo)(DataProvider.Instance _.GetPortal(portalID, Entities.Host.Host.ContentLocale.ToString)) This will fi ll the PortalInfo object (EntitiesPortalPortalInfo.vb), which as we mentioned, holds the portal information. This object in turn is returned to the GetCachedObject method. Once this is complete, the object is then cached to help prevent the need to call the database during the next request for the portal information. There is also a section of code (not shown) that verifi es whether the object was successfully stored in the cache and adds an entry to the event log if the item failed to be cached. ' if we retrieved a valid object and we are using cachingIf objObject IsNot Nothing AndAlso timeOut > 0 Then' save the object in the cacheDataCache.SetCache(cacheItemArgs.CacheKey, objObject, _cacheItemArgs.CacheDependency, Cache.NoAbsoluteExpiration, _TimeSpan.FromMinutes(timeOut), cacheItemArgs.CachePriority, _cacheItemArgs.CacheCallback)…End If After the portal settings are saved, the properties of the current tab information are retrieved and populated in the ActiveTab property. The current tab is retrieved by using the tabID that was originally passed to the constructor. This is handled by the VerifyPortalTab method and done by getting a list of all of the tabs for the current portal. Like the portal settings themselves, the tabs are saved in cache to boost performance. The calls to the caching provider, this time, are handled by the TabController (EntitiesTabsTabController.vb). In the last VerifyPortalTab method, the code will loop through all of the host and non-host tabs, returned by the TabController, for the site until the current tab is located. ' find the tab in the portalTabs collectionIf TabId <> Null.NullInteger ThenIf portalTabs.TryGetValue(TabId, objTab) Then'Check if Tab has been deleted (is in recycle bin)If Not (objTab.IsDeleted) ThenMe.ActiveTab = objTab.Clone()isVerified = TrueEnd IfEnd IfEnd If' find the tab in the hostTabs collectionIf Not isVerified AndAlso TabId <> Null.NullInteger ThenIf hostTabs.TryGetValue(TabId, objTab) Then'Check if Tab has been deleted (is in recycle bin)If Not (objTab.IsDeleted) ThenMe.ActiveTab = objTab.Clone()isVerified = TrueEnd IfEnd IfEnd If If the tab was not found in either of these collections, the code attempts to use the splash page, home page, or the fi rst page of the non-host pages. After the current tab is located, further handling of some of its properties is done back in the GetPortalSettings method. This includes formatting the path for the skin and default container used by the page, as well as collecting information on the modules placed on the page. Me.ActiveTab.SkinSrc = _SkinController.FormatSkinSrc(Me.ActiveTab.SkinSrc, Me)Me.ActiveTab.SkinPath = _SkinController.FormatSkinPath(Me.ActiveTab.SkinSrc)…For Each kvp As KeyValuePair(Of Integer, ModuleInfo) In _objModules.GetTabModules(Me.ActiveTab.TabID)' clone the module object _( to avoid creating an object reference to the data cache )Dim cloneModule As ModuleInfo = kvp.Value.Clone' set custom propertiesIf Null.IsNull(cloneModule.StartDate) ThencloneModule.StartDate = Date.MinValueEnd IfIf Null.IsNull(cloneModule.EndDate) ThencloneModule.EndDate = Date.MaxValueEnd If' containerIf cloneModule.ContainerSrc = "" ThencloneModule.ContainerSrc = Me.ActiveTab.ContainerSrcEnd IfcloneModule.ContainerSrc = _SkinController.FormatSkinSrc(cloneModule.ContainerSrc, Me)cloneModule.ContainerPath = _SkinController.FormatSkinPath(cloneModule.ContainerSrc)' process tab panesIf objPaneModules.ContainsKey(cloneModule.PaneName) = False ThenobjPaneModules.Add(cloneModule.PaneName, 0)End IfcloneModule.PaneModuleCount = 0If Not cloneModule.IsDeleted ThenobjPaneModules(cloneModule.PaneName) = _objPaneModules(cloneModule.PaneName) + 1cloneModule.PaneModuleIndex = _objPaneModules(cloneModule.PaneName) - 1End IfMe.ActiveTab.Modules.Add(cloneModule)Next We have now discussed some of the highlights of the PortalSettings object as well as how it is populated with the information it contains. In doing so, we also saw abrief example of the robust caching service provided by DotNetNuke. You will see the PortalSettings class referenced many times in the core DotNetNuke code, so gaining a good understanding of how this class works will help you to become more familiar with the DNN code base. You will also fi nd this object to be very helpful while building custom extensions for DotNetNuke. The caching provider itself is a large topic, and reaches beyond the scope of this article. However, simply understanding how to work with it in the ways shown in these examples should satisfy the needs of most developers. It is important to note that, you can get any type of object cached by DNN by passing in a key for your object to DataCache.SetCache method, together with the data, and some optional arguments. While fetching the object back from DataCache.GetCache, you pass in the same key, and check the result. A non-null (non-Nothing in VB) return value means you have fetched the object successfully from the cache, otherwise you would need to fetch it from the database.
Read more
  • 0
  • 0
  • 3095

article-image-understanding-dotnetnuke-core-architecture-extension
Packt
06 Apr 2010
8 min read
Save for later

Understanding the DotNetNuke Core Architecture- An Extension

Packt
06 Apr 2010
8 min read
The global files The Global.asax.vb and Globals.vb files share similar names but the parts they play in DotNetNuke are vastly different. The Global.asax.vb is used by DotNetNuke to handle application-level events raised by the ASP.NET runtime. The Globals.vb file, on the other hand, is a public module (which is the same as a static class in C#) that contains global utility functions. Before we take a look at these fi les, we first want to look at what object is being passed around in these transactions. Global.asax.vb Much of the logic that used to reside in the Global.asax.vb fi le has now been abstracted to the HTTP modules. We will look into the code that remains. Application_Start When the fi rst request is made to your application (when the fi rst user accesses the portal), a pool of HttpApplication instances are created and the Application_Start event is fi red. This will (theoretically) fire just once and on the first HttpApplication object in the pool. When there is inactivity on your portal for a certain amount of time, the application (or application pool) will be recycled. When the pool is recycled, your application will restart (and this event will fi re again) when the next request is made for your application. As the new version of DotNetNuke uses the .NET website structure, you will find the Global.asax.vb fi le in the App_Code folder. In the Application_Start, we are loading all of the confi gured providers to ensure they are available to the rest of the framework when needed. These are performed in the Application_Start because we want them to be called only once. Private Sub Application_Start(ByVal Sender As Object, ByVal E AsEventArgs)If Config.GetSetting("ServerName") = "" ThenServerName = Server.MachineNameElseServerName = Config.GetSetting("ServerName")End IfComponentFactory.Container = New SimpleContainer()'Install most Providers as Singleton LifeStyleComponentFactory.InstallComponents _(New ProviderInstaller("data", GetType(DotNetNuke.Data.DataProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("caching", GeType(Services.Cache.CachingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("logging", GetType(Services.Log.EventLog.LoggingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("scheduling", GetType(Services.Scheduling.SchedulingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("searchIndex", GetType(Services.Search.IndexingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("searchDataStore", GetType(Services.Search.SearchDataStoreProvider)))ComponentFactory.InstallComponents_(New ProviderInstaller("friendlyUrl", GetType(Services.Url.FriendlyUrl.FriendlyUrlProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("members", GetType(DotNetNuke.Security.Membership.MembershipProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("roles", GetType(DotNetNuke.Security.Roles.RoleProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("profiles", GetType(DotNetNuke.Security.Profile.ProfileProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("permissions", GetType(DotNetNuke.Security.Permissions.PermissionProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("outputCaching", GetType(DotNetNuke.Services.OutputCache.OutputCachingProvider)))ComponentFactory.InstallComponents _(New ProviderInstaller("moduleCaching", GetType(DotNetNuke.Services.ModuleCache.ModuleCachingProvider)))Dim provider As DotNetNuke.Security.Permissions.PermissionProvider = _DotNetNuke.ComponentModel.ComponentFactory.GetComponent _(Of DotNetNuke.Security.Permissions.PermissionProvider)()If provider Is Nothing ThenComponentFactory.RegisterComponentInstance _(Of DotNetNuke.Security.Permissions.PermissionProvider) _(New DotNetNuke.Security.Permissions.PermissionProvider())End If'Install Navigation and Html Providers as NewInstanceLifestyle (ie a new instance is generated each time the type isrequested, as there are often multiple instances on the page)ComponentFactory.InstallComponents _(New ProviderInstaller("htmlEditor", _GetType(Modules.HTMLEditorProvider.HtmlEditorProvider), _ComponentLifeStyleType.Transient))ComponentFactory.InstallComponents _(New ProviderInstaller("navigationControl", _GetType(Modules.NavigationProvider.NavigationProvider), _ComponentLifeStyleType.Transient))End Sub In previous versions of DotNetNuke, there was a great deal happening in this method. However, this code has been moved into various methods inside of the Initialize class. This was done to support the integrated pipeline mode of IIS 7. If you would like to take a look at what is happening inside of the Initialize class, it can be found in the Common folder of the DotNetNuke.Library project. Examining Application_BeginRequest The Application_BeginRequest is called for each request made to your application. In other words, this will fi re every time a page (tab), or other web request handlers such as a web service or an ashx handler, is accessed in your portal. This section is used to implement the scheduler built into DotNetNuke. Starting in version 2.0, two items, "users online" and "site log", require recurring operations. Also in this method is the call to the Initialize.Init() method that was moved out of the Appli cation_Startup method as mentioned previously. You can fi nd out more about the scheduler by looking at the DotNetNuke Scheduler.pdf document (only if you download the documentation pack). Also note that, there is a host setting that defi nes the running mode of a scheduler, you can check for a scheduler run on every request to your portal, or run the scheduler in a timer mode. Private Sub Global_BeginRequest(ByVal sender As Object, _ByVal e As EventArgs) Handles Me.BeginRequestDim app As HttpApplication = CType(sender, HttpApplication)Dim Request As HttpRequest = app.RequestIf Request.Url.LocalPath.ToLower.EndsWith("scriptresource.axd") _OrElse Request.Url.LocalPath.ToLower.EndsWith("webresource.axd") _OrElse Request.Url.LocalPath.ToLower.EndsWith("gif") _OrElse Request.Url.LocalPath.ToLower.EndsWith("jpg") _OrElse Request.Url.LocalPath.ToLower.EndsWith("css") _OrElse Request.Url.LocalPath.ToLower.EndsWith("js") ThenExit SubEnd If' all of the logic which was previously in Application_Start' was moved to Init() in order to support IIS7 integrated pipelinemode' ( which no longer provides access to HTTP context withinApplication_Start )Initialize.Init(app)'run schedule if in Request modeInitialize.RunSchedule(Request)End Sub The Globals.vb file As part of the namespace-reorganization effort associated with DotNetNuke version 3.0, general utility functions, constants, and enumerations have all been placed in a public module (as just mentioned, module here refers to VB.NET module keyword, not a DotNetNuke module) named Globals . As items in a .NET module are inherently shared, you do not need to instantiate an object in order to use the functions found here. In this module, you will find not only global constants, as shown in the following code: Public Const glbRoleAllUsers As String = "-1"Public Const glbRoleSuperUser As String = "-2"Public Const glbRoleUnauthUser As String = "-3"Public Const glbRoleNothing As String = "-4"Public Const glbRoleAllUsersName As String = "All Users"Public Const glbRoleSuperUserName As String = "Superuser"Public Const glbRoleUnauthUserName As String ="Unauthenticated Users"Public Const glbDefaultPage As String = "Default.aspx"Public Const glbHostSkinFolder As String = "_default"Public Const glbDefaultControlPanel As String = "Admin/ControlPanel/IconBar.ascx"Public Const glbDefaultPane As String = "ContentPane"Public Const glbImageFileTypes As String = "jpg,jpeg,jpe,gif,bmp,png,swf"Public Const glbConfigFolder As String = "Config"Public Const glbAboutPage As String = "about.htm"Public Const glbDotNetNukeConfig As String = "DotNetNuke.config"Public Const glbSuperUserAppName As Integer = -1Public Const glbProtectedExtension As String = ".resources"Public Const glbEmailRegEx As String = "b[a-zA-Z0-9._%-+']+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}b"Public Const glbScriptFormat As String = "<script type=""text/javascript"" src=""{0}"" ></script>"   but a tremendous number of public functions to help you do everything, from retrieving the domain name, as shown: Public Function GetDomainName(ByVal Request As HttpRequest, ByValParsePortNumber As Boolean) As String to setting the focus on a page: Public Sub SetFormFocus(ByVal control As Control) This one file contains a wealth of information for the developer. As there are more than 3070 lines in the fi le and the methods are fairly straightforward, we will not be stepping through this code. The Globals.vb fi le can now be found in the DotNetNuke.Library project in the Common folder. Putting it all together We have spent some time looking at some of the major pieces that make up the core architecture. You might be asking yourself how all this works together. In this section, we will walk you through an overview version of what happens when a user requests a page on your portal. A shown in the preceding diagram, when a user requests any page on your portal, the HTTP Modules that have been declared in the web.config file are hooked into the pipeline. Typically, these modules use the Init method to attach event handlers to application events. The request then goes through the Global.asax page. As just mentioned, some of the events fi red here will be intercepted and processed by the HTTP modules, but the call to run the scheduler will happen in this fi le. Next, the page that was requested, Default.aspx, will be processed. As we stated at the beginning of this article, all requests are sent to the Default.aspx page and all the controls and skins needed for the page are created dynamically by reading the tabID from the requested URL. So let's begin by looking at the HTML for this page.
Read more
  • 0
  • 0
  • 1426

article-image-organizing-your-content-effectively-using-joomla-15-sequel
Packt
06 Apr 2010
5 min read
Save for later

Organizing your Content Effectively using Joomla 1.5- A Sequel

Packt
06 Apr 2010
5 min read
Time for action - move content from one category to another The Activities section contains some articles that you might want to move to the News section. Let's clean up the Activities - Meetings category and move anything topical into the News - General News category: Navigate to Content | Article Manager. From the list, select the items you want to move from the Meetings category to the General News category. In this example, we've selected two articles: Click on Move on the toolbar. You'll be taken to the Move Articles screen: In the Move to Section/Category list, select News/General News. At the far right-hand side, you can check which articles are being moved. Click on Save. In the Article Manager screen, the three articles are now part of the News section. You can check this by clicking on the News link on the frontend Main Menu. What just happened? You've stood the real life challenge of content management! Now, you're not only able to create a sound content structure for your website, but you also know how to improve on it. By adding a new container for all news items and moving existing news content there you've now made room for growth on the SRUP site. Have a go hero - moving entire categories Sometimes you might want to move an entire category and all its contents to another section. Try this out for yourself-it's not much different from moving articles. Imagine you'd like to move the Reviews category from the Ugly Paintings section to another section. In the Category Manager, select the category you want to move and click on the Move button. Select the section you want to move things to, and click on Save. It's just as straightforward to move the entire category including all of its article contents back again. This flexibility is great when you're setting up or rearranging your site. Renaming sections or categories As we've just seen, Joomla! allows you to easily rearrange your site structure and its contents. You can also rename sections and categories that already contain articles; no content will be lost. Time for action - rename a section On your client's website there's an Activities section. Your client wants to make it clear this section is not about activities organized by other art societies-it's only about SRUP. Could you please change the name of the section to SRUP Activities? It's a breeze. Navigate to Content | Section Manager and click on the title of the Activities section to open it for editing. In the Section: [Edit] screen, change the Title to SRUP Activities. In the Alias: field, remove the existing alias (remember, the Alias is Joomla!'s internal name for the article used when creating user-friendly URLs). Leave this box blank; Joomla! will fill it with srup-activities when you apply or save your changes. You can check that now by clicking on Apply. You'll notice the Alias box is filled out automatically. Click on Save. What just happened? By changing a section or category name, all of Joomla!'s internal references to the name are updated automatically. All articles and categories in the renamed section will reflect the changes you made. In the Article Manager, for example, all items that belonged to the Activities section are now updated to show they are in the SRUP Activities section. No manual labor here and more importantly, nothing is lost! On the frontend, the new section name shows up on the section overview page when the user clicks on the Activities link: Have a go hero - name and rename! Using appropriate, short, and descriptive labels for sections and categories (and for the menu links pointing to them) is really essential. After all, these are the words that guide your visitors to the content you want them to discover. It's a good idea to tweak these labels until you're perfectly happy with them. To modify the names of categories, navigate to the Category Manager; it's similar to changing section names. Maybe you would like to change menu link labels too, as these don't automatically change with the category or section name. Try to find short and appropriate menu link labels. To change menu link labels, navigate to the Main Menu, select any of the menu items and change what's in the Title field (that is, SRUP Activities). When changing Titles (of Sections/Categories/Menu Link Items) make sure to clear the contents of the Alias box. Joomla! will automatically create an Alias for the new Title. Changing section and category settings You've already created a good deal of sections and categories without altering any of the default settings. In some cases, however, you might want some more control over the section or category you're editing. In the table below you can see the options that are available in the Section/Category: [New] or Section/Category: [Edit] screen. Basically, you can customize these settings for two purposes: To determine whether a section or category is visible (and which user groups can see it) To add a short descriptive text whenever the section or category contents are displayed. We'll cover both the Section and Category edit screen in the overview next, as all settings and options are identical. The only difference is that when adding a category, Joomla! wants you to specify the section that holds the new category. This is what the Section: [New] and the Category: [New] screen look like:
Read more
  • 0
  • 0
  • 974

article-image-installation-and-getting-started-firebug
Packt
05 Apr 2010
3 min read
Save for later

Installation and Getting Started with Firebug

Packt
05 Apr 2010
3 min read
What is Firebug? Firebug is a free, open source tool that is available as a Mozilla Firefox extension, and allows debugging, editing, and monitoring of any website's CSS, HTML, DOM, and JavaScript. It also allows performance analysis of a website. Furthermore, it has a JavaScript console for logging errors and watching values. Firebug has many other tools to enhance the productivity of today's web developer. Firebug integrates with Firefox to put a wealth of development tools at our fingertips while we browse a website. Firebug allows us to understand and analyze the complex interactions that take place between various elements of any web page when it is loaded by a browser. Firebug simply makes it easier to develop websites/applications. It is one of the best web development extensions for Firefox. Firebug provides all the tools that a web developer needs to analyze, debug, and monitor JavaScript, CSS, HTML, and AJAX. It also includes a debugger, error console, command line, and a variety of useful inspectors. Although Firebug allows us to make changes to the source code of our web page, the changes are made to the copy of the HTML code that has been sent to the browser by the server. Any changes to the code are made in the copy that is available with the browser. The changes don't get reflected in the code that is on the server. So, in order to ensure that the changes are permanent, corresponding changes have to be made in the code that resides on the server. The history of Firebug Firebug was initially developed by Joe Hewitt, one of the original Firefox creators, while working at Parakey Inc. Facebook purchased Parakey in July, 2007. Currently, the open source development and extension of Firebug is overseen by the Firebug Working Group. It has representation from Mozilla, Google, Yahoo, IBM, Facebook, and many other companies. Firebug 1.0 Beta was released in December 2006. Firebug usage has grown very fast since then. Approximately 1.3 million users have Firebug installed as of January 2009. The latest version of Firebug is 1.5. Today, Firebug has a very open and thriving community. Some individuals as well as some companies have developed very useful plugins on top of Firebug. The need for Firebug During the 90s, websites were mostly static HTML pages, JavaScript code was considered a hack, and there were no interactions between page components on the browser side. The situation is not the same anymore. Today's websites are a product of several distinct technologies and web developers must be proficient in all of them—HTML, CSS, JavaScript, DOM, and AJAX, among others. Complex interactions happen between various page components on the browser side. However, web browsers have always focused on the needs of the end users; as a result, web developers have long been deprived of a good tool on the client/browser side to help them develop and debug their code. Firebug fills this gap very nicely—it provides all the tools that today's web developer needs in order to be productive and efficient with code that runs in the browser. Firebug capabilities Firebug has a host of features that allow us to do the following (and much more!): Inspect and edit HTML Inspect and edit CSS and visualize CSS metrics Use a performance tuning application Profile and debug JavaScript Explore the DOM Analyze AJAX calls
Read more
  • 0
  • 0
  • 3550
article-image-configuring-mysql
Packt
01 Apr 2010
14 min read
Save for later

Configuring MySQL

Packt
01 Apr 2010
14 min read
Let's get started. Setting up a fixed InnoDB tablespace When using the InnoDB storage engine of MySQL, the data is typically not stored in a per-database or per-table directory structure, but in several dedicated files, which collectively contain the so-called tablespace. By default (when installing MySQL using the configuration wizard) InnoDB is confi gured to have one small file to store data in, and this file grows as needed. While this is a very fl exible and economical confi guration to start with, this approach also has some drawbacks: there is no reserved space for your data, so you have to rely on free disk space every time your data grows. Also, if your database grows bigger, the file will grow to a size which makes it hard to handle—a dozen files of 1 GB each are typically easier to manage than one clumsy 12 GB file. Large data files might, for example, cause problems if you try to put those files into an archive for backup or data transmission purposes. Even if the 2 GB limit is not present any more for the current file systems, many compression programs still have problems dealing with large files. And finally, the constant adaptation of the file in InnoDB's default configuration size will cause a (small, but existent) performance hit if your database grows. The following recipe will show you how to define a fixed tablespace for your InnoDB installation, by which you can avoid these drawbacks of the InnoDB default configuration. Getting ready To install a fixed tablespace, you will have to reflect about some aspects: how much tablespace should be reserved for your database, and how to size the single data files which in sum constitute the tablespace. Note that once your database completely allocates your tablespace, you will run into table full errors (error code 1114) when trying to add new data to your database. Additionally, you have to make sure that your current InnoDB tablespace is completely empty. Ideally, you should set up the tablespace of a freshly installed MySQL instance, in which case this prerequisite is given. To check whether any InnoDB tables exist in your database, execute the following statement and delete the given tables until the result is empty: SELECT TABLE_SCHEMA, TABLE_NAME FROM information_schema.tables WHERE engine="InnoDB"; If your database already contains data stored in InnoDB tables that you do not want to lose, you will have to create a backup of your database and recover the data from it when you are done with the recipe. Please refer to the chapter Backing Up and Restoring MySQL Data for further information on this. And finally, you have to make sure that the InnoDB data directory (as defined by the innodb_data_home_dir variable) features sufficient free disk space to store the InnoDB data files. For the following example, we will use a fixed tablespace with a size of 500 MB and a maximal file size of 200 MB. How to do it... Open the MySQL configuration file (my.ini or my.cnf) in a text editor. Identify the line starting with innodb_data_file_path in the [mysqld] section. If no such line exists, add the line to the file. Change the line innodb_data_file_path to read as follows: innodb_data_file_path=ibdata1:200M;ibdata2:200M;ibdata3:100M Save the changed configuration file. Shut down your database instance (if running). Delete previous InnoDB data files (typically called ibdata1, ibdata2, and so on) from the directory defined by the innodb_data_home_dir variable. Delete previous InnoDB logfiles (named ib_logfile0, ib_logfile1, so on) from the directory defined by the innodb_log_group_home_dir variable. If innodb_log_group_home_dir is not configured explicitly, it defaults to the datadir directory. Start your database. Wait for all data and log files to be created. Depending on the size of your tablespace and the speed of your disk system, creation of InnoDB data fi les can take a significant amount of time (several minutes is not an uncommon time for larger installations). During this initialization sequence, MySQL is started but it will not accept any requests. How it works... Steps 1 through 4—and particularly 3—cover the actual change to be made to the MySQL configuration, which is necessary to adapt the InnoDB tablespace settings. The value of the innodb_data_file_path variable consists of a list of data file definitions that are separated by semicolons. Each data file definition is constructed of a fi le name and a file size with a colon as a separator. The size can be expressed as a plain numeric value, which defines the size of the data file in bytes. If the numeric value has a K, M, or G postfix, the number is interpreted as Kilobytes, Megabytes, or Gigabytes respectively. The list length is not limited to the three entries of our example; if you want to split a large tablespace into relatively small files, the list can easily contain dozens of data file definitions. If your tablespace consists of more than 10 files, we propose naming the first nine files ibdata01 through ibdata09 (instead of ibdata1 and so forth; note the zero), so that the files are listed in a more consistent order when they are displayed in your file browser or command line interface. Step 5 is prerequisite to the steps following after it, as deletion of vital InnoDB files while the system is still running is obviously not a good idea. In step 6, old data files are deleted to prevent collision with the new files. If InnoDB detects an existing file whose size differs from the size defined in the innodb_data_file_path variable, it will not initialize successfully. Hence, this step ensures that new, properly saved files can be created during the next MySQL start. Note that deletion of the InnoDB data files is only suffi cient if all InnoDB tables were deleted previously (as discussed in the Getting ready section). Alternatively, you could delete all *.frm files for InnoDB tables from the MySQL data directory, but we do not encourage this approach (clean deletion using DROP TABLE statements should be preferred over manual intervention in MySQL data directories whenever possible). Step 7 is necessary to prevent InnoDB errors after the data files are created, as the InnoDB engine refuses to start if the log files are older than the tablespace files. With steps 8 and 9, the new settings take effect. When starting the database for the first time after changes being made to the InnoDB tablespace configuration, take a look at the MySQL error log to make sure the settings were accepted and no errors have occurred. The MySQL error log after the first start with the new settings will look similar to this:   InnoDB: The first specified data file E:MySQLInnoDBTestibdata1 didnot exist:InnoDB: a new database to be created!091115 21:35:56 InnoDB: Setting file E:MySQLInnoDBTestibdata1 sizeto 200 MBInnoDB: Database physically writes the file full: wait...InnoDB: Progress in MB: 100 200...InnoDB: Progress in MB: 100091115 21:36:19 InnoDB: Log file .ib_logfile0 did not exist: new tobe createdInnoDB: Setting log file .ib_logfile0 size to 24 MBInnoDB: Database physically writes the file full: wait......InnoDB: Doublewrite buffer not found: creating newInnoDB: Doublewrite buffer createdInnoDB: Creating foreign key constraint system tablesInnoDB: Foreign key constraint system tables created091115 21:36:22 InnoDB: Started; log sequence number 0 0091115 21:36:22 [Note] C:Program FilesMySQLMySQL Server 5.1binmysqld: ready for connections.Version: '5.1.31-community-log' socket: '' port: 3306 MySQLCommunity Server (GPL)   There's more... If you already use a fixed tablespace, and you want to increase the available space, you can simply append additional files to your fixed tablespace by adding additional data file definitions to the current innodb_data_file_path variable setting. If you simply append additional files, you do not have to empty your tablespace first, but you can change the confi guration and simply restart your database. Nevertheless, as with all changes to the confi guration, we strongly encourage creating a backup of your database first.   Setting up an auto-extending InnoDB tablespace The previous recipe demonstrates how to define a tablespace with a certain fixed size. While this provides maximum control and predictability, you have to block disk space based on the estimate of the maximum size required in the foreseeable future. As long as you store less data in your database than the reserved tablespace allows for, this basically means some disk space is wasted. This especially holds true if your setting does not allow for a separate file system exclusively for your MySQL instance, because then other applications compete for disk space as well. In these cases, a dynamic tablespace that starts with little space and grows as needed could be an alternative. The following recipe will show you how to achieve this. Getting ready When defining an auto-extending tablespace, you should first have an idea about the minimum tablespace requirements of your database, which will set the initial size of the tablespace. Furthermore, you have to decide whether you want to split your initial tablespace into files of a certain maximum size (for better file handling). If the above settings are identical to the current settings and you only want to make your tablespace grow automatically if necessary, you will be able to keep your data. Otherwise, you have to empty your current InnoDB tablespace completely (please refer to the previous recipe Setting up a fixed InnoDB tablespace for details). As with all major confi guration changes to your database, we strongly advise you to create a backup of your data first. If you have to empty your tablespace, you can use this backup to recover your data after the changes are completed. Again, please refer to the chapter Backing Up and Restoring MySQL Data for further information on this. And as before, you have to make sure that there is enough disk space available in the innodb_data_home_dir directory—not only for the initial database size, but also for the anticipated growth of your database. The recipe also requires you to shut down your database temporarily; so you have to make sure all clients are disconnected while performing the required steps to prevent conflicting access. As the recipe demands changes to your MySQL confi guration file (my.cnf or my.ini), you need write access to this file. For the following example, we will use an auto-extending tablespace with an initial size of 100 MB and a file size of 50 MB. How to do it... Open the MySQL configuration file (my.ini or my.cnf) in a text editor. Identify the line starting with innodb_data_file_path in the [mysqld] section. If no such line exists, add the line to the file. Change the line innodb_data_file_path to read as follows: innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend Note that no file defi nition except the last one must have the :autoextend option; you will run into errors otherwise. Save the changed confi guration file. Shut down your database instance (if running). Delete previous InnoDB data files (typically called ibdata1, ibdata2, and so on) from the directory defi ned by the innodb_data_home_dir variable. Delete previous InnoDB logfiles (named ib_logfile0, ib_logfile1, and so on) from the directory defined by the innodb_log_group_home_dir variable. If innodb_log_group_home_dir is not configured explicitly, it defaults to the datadir directory Start your database. Wait for all data and log files to be created. Depending on the size of your tablespace and the speed of your disk system, creation of InnoDB data files can take a signifi cant amount of time (several minutes is not an uncommon time for larger installations). During this initialization sequence, MySQL is started but will not accept any requests. When starting the database for the first time after changes being made to the InnoDB tablespace configuration, take a look at the MySQL error log to make sure the settings were accepted and no errors have occurred. How it works... The above steps are basically identical to the steps of the previous recipe Setting up a fixed InnoDB tablespace, the only difference being the definition of the innodb_data_file_path variable. In this recipe, we create two files of 50 MB size, the last one having an additional :autoextend property. If the innodb_data_file_path variable is not set explicitly, it defaults to the value ibdata1:10M:autoextend. As data gets inserted into the database, parts of the tablespace will be allocated. As soon as the 100 MB of initial tablespace is not sufficient any more, the file ibdata2 will become larger to match the additional tablespace requirements. Note that the :autoextend option causes the tablespace files to be extended automatically, but they are not automatically reduced in size again if the space requirements decrease. Please refer to the Decreasing InnoDB tablespace recipe for instructions on how to free unused tablespace. There's more... The recipe only covers the basic aspects of auto-extending tablespaces; the following sections provide insight into some more advanced topics. Making an existing tablespace auto-extensible If you already have a database with live data in place and you want to change your current fixed configuration to use the auto-extension feature, you can simply add the :autoextend option to the last file definition. Let us assume a current configuration like the following: innodb_data_file_path=ibdata1:50M;ibdata2:50M The respective configuration with auto-extension will look like this: innodb_data_file_path=ibdata1:50M;ibdata2:50M:autoextend In this case, do not empty the InnoDB tablespace first, you can simply change the configuration file and restart your database, and you should be fine. As with all configuration changes, however, we strongly recommend to back up your database before editing these settings even in this case. Controlling the steps of tablespace extension The amount by which the size of the auto-extending tablespace file is increased is controlled by the innodb_autoextend_increment variable. The value of this variable defines the number of Megabytes by which the tablespace is enlarged. By default, 8 MB are added to the file if the current tablespace is no longer sufficient. Limiting the size of an auto-extending tablespace If you want to use an auto-extending tablespace, but also want to limit the maximum size your tablespace will grow to, you can add a maximum size for the auto-extended tablespace file by using the :autoextend:max:[size] option. The [size] portion is a placeholder for a size definition using the same notation as the size description for the tablespace file itself, which means a numeric value and an optional K, M, or G modifier (for sizes in Kilo-, Mega-, and Gigabytes). As an example, if you want to have a tiny initial tablespace of 10 MB, which is extended as needed, but with an upper limit of 2 GB, you would enter the following line to your MySQL configuration file: innodb_data_file_path=ibdata1:10M:autoextend:max:2G Note that if the maximum size is reached, you will run into errors when trying to add new data to your database. Adding a new auto-extending data file Imagine an auto-extending tablespace with an auto-extended file, which grew so large over time that you want to prevent the file from growing further and want to append a new auto-extending data file to the tablespace. You can do so using the following steps: Shut down your database instance. Look up the exact size of the auto-extended InnoDB data file (the last file in your current configuration). Put the exact size as the tablespace fi le size definition into the innodb_data_file_path configuration (number of bytes without any K, M, or G modifier), and add a new auto-extending data file. Restart your database. As an example, if your current confi guration reads ibdata1:10M:autoextend and the ibdata1 file has an actual size of 44,040,192 bytes, change configuration to innodb_data_file_path=ibdata1:44040192;ibdata2:10M:autoextend:max:2G.  
Read more
  • 0
  • 0
  • 3091

article-image-managing-data-mysql
Packt
01 Apr 2010
8 min read
Save for later

Managing Data in MySQL

Packt
01 Apr 2010
8 min read
Exporting data to a simple CSV file While databases are a great tool to store and manage your data, you sometimes need to extract some of the data from your database to use it in another tool (a spreadsheet application being the most prominent example for this). In this recipe, we will show you how to utilize the respective MySQL commands for exporting data from a given table into a fi le that can easily be imported by other programs. Getting ready To step through this recipe, you will need a running MySQL database server and a working installation of a SQL client (like MySQL Query Browser or the mysql command line tool). You will also need to identify a suitable export target, which has to meet the following requirements: The MySQL server process must have write access to the target file The target file must not exist The export target file is located on the machine that runs your MySQL server, not on the client side! If you do not have file access to the MySQL server, you could instead use export functions of MySQL clients like MySQL Query Browser. In addition, a user with FILE privilege is needed (we will use an account named sample_install for the following steps; see also Chapter 8 Creating an installation user). Finally, we need some data to export. Throughout this recipe, we will assume that the data to export is stored in a table named table1 inside the database sample. As export target, we will use the file C:/target.csv (MySQL accepts slashes instead of backslashes in Windows path expressions). This is a file on the machine that runs the MySQL server instance, so in this example MySQL is assumed to be running on a Windows machine. To access the results from the client, you have to have access to the file (for example, using a fi le share or executing the MySQL client on the same machine as the server). How to do it... Connect to the database using the sample_install account. Issue the following SQL command: mysql> SELECT * FROM sample.table1 INTO OUTFILE 'C:/target.csv'FIELDS ENCLOSED BY '"' TERMINATED BY ';' ESCAPED BY '"' LINESTERMINATED BY 'rn'; Please note that when using a backslash instead of a slash in the target file's path, you have to use C:target.csv (double backslash for escaping) instead. If you do not give a path, but only a fi le name, the target fi le will be placed in the data directory of the currently selected schema of your MySQL server. How it works... In the previous SQL statement, a file C:/target.csv was created, which contains the content of the table sample.table1. The file contains a separate line for each row of the table, and each line is terminated by a sequence of a carriage return and a line feed character. This line ending was defined by the LINES TERMINATED BY 'rn' portion of the command. Each line contains the values of each column of the row. The values are separated by semicolons, as stated in the TERMINATED BY ';' clause. Every value is enclosed by a double quotation mark ("), which results from the FIELDS ENCLOSED BY '"' option. When writing the data to the target fi le, no character conversion takes place; the data is exported using the binary character set. This should be kept in mind especially when importing tables with different character sets for some of its values. You might wonder why we chose the semicolon instead of a comma as the field separator. This is simply because of a greatly improved Microsoft Excel compatibility (you can simply open the resulting files), without the need to import external data from the fi les. But you can, however, open these fi les in a different spreadsheet program (like OpenOffice.org Calc) as well. If you think the usage of semicolons is in contradiction to the notion of a CSV file, think of it as a Character Separated File. The use of double quotes to enclose single values prevents problems when field values contain semicolons (or generally the field separator character). These are not recognized as field separators if they are enclosed in double quotes. There's more... While the previous SELECT … INTO OUTFILE statement will work well in most cases, there are some circumstances in which you still might encounter problems. The following topics will show you how to handle some of those. Handling errors if the target fi le already exists If you try to execute the SELECT … INTO OUTFILE statement twice, an error File 'C:/target.csv' already exists occurs. This is due to a security feature in MySQL that makes sure that you cannot overwrite existing fi les using the SELECT … INTO OUTFILE statement. This makes perfect sense if you think about the consequences. If this were not the case, you could overwrite the MySQL data files using a simple SELECT because MySQL server needs write access to its data directories. As a result, you have to choose different target files for each export (or remove old files in advance). Unfortunately, it is not possible to use a non-constant file name (like a variable) in the SELECT … INTO OUTFILE export statement. If you wish to use different file names, for example, with a time stamp as part of the file name, you have to construct the statement inside a variable value before executing it:   mysql> SET @selInOutfileCmd := concat("SELECT * FROM sample.table1 INTOOUTFILE 'C:/target-", DATE_FORMAT(now(),'%Y-%m-%d_%H%i%s'), ".csv' FIELDSENCLOSED BY '"' TERMINATED BY ';' ESCAPED BY '"' LINES TERMINATED BY'rn';");mysql> PREPARE statement FROM @selInOutfileCmd;mysql> EXECUTE statement; The first SET statement constructs a string, which contains a SELECT statement. While it is not allowed to use variables for statements directly, you can construct a string that contains a statement and use variables for this. With the next two lines, you prepare a statement from the string and execute it. Handling NULL values Without further handling, NULL values in the data you export using the previous statement would show up as "N in the resulting file. This combination is not recognized, for example, by Microsoft Excel, which breaks the file (for typical usage). To prevent this, you need to replace NULL entries by appropriate values. Assuming that the table sample.table1 consists of a numeric column a and a character column b, you should use the following statement: mysql> SELECT IFNULL(a, 0), IFNULL(b, "NULL") FROM sample.table1 INTOOUTFILE 'C:/target.csv' FIELDS ENCLOSED BY '"' TERMINATED BY ';' ESCAPEDBY '"' LINES TERMINATED BY 'rn'; The downside to this approach is that you have to list all fi elds in which a NULL value might occur. Handling line breaks If you try to export values that contain the same character combination used for line termination in the SELECT … INTO OUTFILE statement, MySQL will try to escape the character combination with the characters defined by the ESCAPED BY clause. However, this will not always work the way it is intended. You will typically define rn as the line separators. With this constellation, values that contain a simple line break n will not cause problems, as they are exported without any conversion and can be imported to Microsoft Excel flawlessly. If your values happen to contain a combination of carriage return and line feed, the rn characters will be prepended with an escape character ("rn), but still the target file cannot be imported correctly. Therefore, you need to convert the full line breaks to simple line breaks: mysql> SELECT a, REPLACE(b, 'rn', 'n') FROM sample.table1 INTO OUTFILE'C:/target.csv' FIELDS ENCLOSED BY '"' TERMINATED BY ';' ESCAPED BY '"'LINES TERMINATED BY 'rn'; With this statement, you will export only line breaks n, which are typically accepted for import by other programs. Including headers For better understanding, you might want to include headers in your target fi le. You can do so by using a UNION construct: mysql> (SELECT 'Column a', 'Column b') UNION ALL (SELECT * FROM sample.table1 INTO OUTFILE 'C:/target.csv' FIELDS ENCLOSED BY '"' TERMINATED BY';' ESCAPED BY '"' LINES TERMINATED BY 'rn'); The resulting file will contain an additional first line with the given headers from the first SELECT clause.
Read more
  • 0
  • 0
  • 3679

article-image-rendering-web-pages-pdf-using-railo-open-source
Packt
01 Apr 2010
6 min read
Save for later

Rendering web pages to PDF using Railo Open Source

Packt
01 Apr 2010
6 min read
As a pre-requisite for this tutorial, you should be familiar with html, css and web technologies in general. You do not need to know any CFML (ColdFusion Markup Language). You should have an understanding of databases, particularly MySQL, which we will use in this example. Server environment For this tutorial, we are using a virtual machine (using VirtualBox) running Windows 2003 Server Standard, IIS, MySQL 5.1, and Railo 3.1. The code we will be writing is not platform specific. You can just as easily implement this on Linux or Mac OSX Server with MySQL and Apache. Website architecture Lets assume that we have the HTML layout code provided to us for our website, and that we need to make it “work” on the web server, pulling its page content from a MySQL database. In addition, we will add the capability for any page to render itself as a PDF for printing purposes. You will want to make sure you have done a few things first: Make sure Railo and MySQL are running on your server (or VM) Make sure you created a MySQL database, and a user that has permission to use your database For development (as opposed to production web servers), try running Railo Express, which runs in a terminal window. This allows you to see the templates it is running, and the full stack trace of errors when they occur. Setting up the Railo datasource The first thing we need to do is setup a Railo datasource. This named datasource will define our database credentials for our website. Open a web browser to the Railo Server Administrator, which is usually located at: http://your.server.com/railo-context/admin/server.cfm. Check the Railo documentation if you have trouble opening up the administrator. Enter your password to login. Once logged in, click on the Services / Datasource link in the left navigation. At the bottom of this page is where you can create a new datasource. Enter a datasource name (Letters and numbers only, no spaces, and start with a letter) and select MySQL as the database type. On the next screen, enter the MySQL server host name or ip address, and username and password for the user you created. All of the other settings can be kept with their default values. Scroll to the bottom and click on the “Create” button to complete the datasource configuration. Railo Administrator will test your connection, so you can confirm that it is setup properly. We created the datasource in the “server” context. When you deploy an application on a production server, you should create your datasources in the “web” context, so that it is only available to the website that needs it. Datasources created in the server context are accessible from any website on the same server. Setting up the website structure In the document root of your website (or in the directory you choose for this tutorial), you will need a couple of files. index.cfm – this is the default document, like index.html or default.htm header.cfm – this is the top portion of web pages, what appears above your page content. This is where you would put your html “design” code. footer.cfm – this is the bottom portion of your web pages, what shows up after your page content. This is where you would put your html “design” code. layout.css – the basic CSS layout for our pages styles.css – the CSS styles for your page content Let's look first at header.cfm: This file contains what you would expect to see at the top of a standard HTML web page, including head, title, meta tags, etc. There are a few different tags included in the content however. Any tags that begin with <cf…> are CFML language tags, that are processed by Railo and removed from the source code before the page is sent to your web browser. Just like PHP or ASP.net code, if somebody views the source of your web page, they won’t see your CFML code, but rather, they will see the html code, and any code that your CFML tags generate. <cfparam name="title" default="Untitled" /> This tag defines and sets a default value for a variable named “title.” This value can be overridden using a <cfset …> tag which we will see later. #title#</cfoutput> Any content inside <cfoutput>…</cfoutput> tags will be included in the output to your web browser. In this case, the title variable is written to the page output. As with all <cf..> tags, the <cfoutput> tags themselves will be removed from the web page output. Anything inside # characters will be evaluated as an expression. So if your code was <cfoutput>title</cfoutput>, then the literal word “title” would be included in your page output. When you put # characters around it, Railo will evaluate the expression and replace it with the result.</cfoutput></cf..> header.cfm also includes the two .css files we need for our layout and styles. These are standard css which should be familiar to you, and won’t be covered in this article. Let's next look at index.cfm <cfset title="Home Page"> This first tag sets a local variable called “title” and sets its value to “Home Page.” <cfinclude template="header.cfm"> This tag includes the file “header.cfm” into the current page, which means that any page output (the html, head, title, etc. tags) will be included in this page’s output. Notice that we set the local variable title in our page, and it gets used in the header.cfm file. Local variables are available to any pages that are included in the requested web page. The “Hello World” content is the main textual content of this web page, and can be any html or CFML generated content you want. After the main content, another <cfinclude…> tag includes footer.cfm, which includes the expected end of page tags such as </body> and </html> Take a look If you open your web browser and browse to index.cfm, you will see your basic web page layout, with a page title, and Hello World content. If you view the page source, you should see the combined content of the header.cfm, index.cfm and footer.cfm, with no <cf…> tags in the output, only pure HTML. You can easily organize and create static web pages like this, and like many other programming languages, structuring your website like this has many benefits. If you make a change to your header or footer, then all your pages inherit the change immediately. Likewise if you design a new layout or style for your site, applying it once to your header and footer then applies it to your entire website.
Read more
  • 0
  • 0
  • 2116
article-image-introduction-railo-open-source
Packt
31 Mar 2010
10 min read
Save for later

Introduction to Railo Open Source

Packt
31 Mar 2010
10 min read
What is Railo? Railo is an open source Java application server that implements CFML (ColdFusion Markup Language), a tag based language from Adobe's commercial product “ColdFusion.” Its performance is excellent, and it includes features that significantly increase productivity. Railo is a relative newcomer, but has been making some impressive ripples in the industry lately. This article is a primer on some of the critical advantages of Railo and why it is worth a serious look for web application development. Isn’t ColdFusion dead? A few years back, an article was published naming 10 technologies that were dead or dying, and to many people's surprise, ColdFusion was in that list. That caused a lot of waves. One thing about CFML developers – they are passionate about their programming language! ColdFusion has seen moderate success in specific vertical markets, but has been notably well accepted by the US Government. In comparison to dominant development languages, CFML never seemed to find real favor with the masses. Since ColdFusion was re-engineered to run entirely on Java, and with the arrival of Adobe Flex a few years ago which integrates Flash and ColdFusion, this has changed quite a bit. Adobe's ColdFusion product integrates so well with Flex that it has spawned new interest. One of the largest complaints about Adobe ColdFusion has always been the price. It’s been my experience that CFML developers consider themselves to be industry peers of LAMP (Linux, Apache, MySQL, PHP) developers, who use all open source tools. The majority of LAMP developers consider their skills much higher than that of CFML developers. This has only fed the fury over the years of CFML developers who claim that the investment in purchasing ColdFusion is a quick return on investment since CFML is so much more productive. Now along comes Railo, offering a free and open source solution to the CFML developers' dreams. Not only is it free, but also it performs fantastic, is stable, and is updated reasonably frequently. This is good news for CFML, which is, in my opinion, highly underrated, mostly due to poor marketing and sales price points over the years. CFML is actually quite a powerful and surprisingly productive language, and was designed to be a RAD (Rapid Application Development) tool. It has grown into a significantly better product, and certainly does deserve more respect than it has had. But enough about CFML, let’s talk about why I find Railo is so impressive and what distinguishes itself from the competition. What can you do with Railo? Perhaps the best way to answer this is to say, “What CAN'T you do with Railo?” The CFML language is essentially a big java tag library. CFML has grown into an impressive library over the years and Railo supports everything that Adobe's product supports that is in mainstream use. (There is some difference between the support as both Railo and Adobe release new versions of their products). The core features of Railo's language provide easy to learn tags for everything from database queries to sending dynamic email messages to scripting connections with ftp and Amazon s3 storage. Pretty much anything you can do with PHP you can do with Railo. Here's the catch – generally speaking, it takes less time to implement a solution using CFML than it does with PHP, ASP.net or pure Java. Use CFML for the basics; Extend using Java. While Railo gives you a LOT of built in functions, the real truth of the situation is that it is Java under the hood. All the tags and functions ultimately get compiled and run as Java byte code. The language is well designed, however, so that you can mix and match your CFML and Java code. For instance, if you wanted to read in a text file, you can use the built in tag CFFILE: <cffile action="read" file="c:webmessage.txt" variable="strContent"></cffile> This reads in the contents of the text file, and stores it in the specified variable. To display that content in the web browser, you would output it like so: <cfoutput>#strContent#</cfoutput> To illustrate how Java can be used directly in your code, this same task can be done using Java objects instead of the built in CFML tags like so: <cfobject type="Java" class=" java.io.FileReader" Action="Create" name="myFileReader"> <cfset Result = fileReader.init("c:webmessage.txt"); <cfoutput>#strContent#</cfoutput> These two small pieces of code achieve the same goals. My point is that the CFML language isn't limited to just CFML, you can instantiate and use any Java object anywhere within your code. This makes the language incredibly flexible, since you can use the CFML tags for quick and easy tasks, and use Java for heavy lifting where needed. Deployment and Development Environments All versions of Railo can be downloaded either as an “express,” “server” or “custom” deployment. The express edition is extremely easy for developers to get up and running and usually involves just decompressing a zip file onto your local system and starting it up. The server package comes along with Caucho Resin, a very high performance java application server. (Side note – some of the tools included with Resin are pretty impressive as well, including their all-java implementation of PHP!). The custom deployment package is for launching Railo on other Java servlet containers like Tomcat or Weblogic. Setting up Railo on a production server wasn't difficult, granted it is a bit more involved than installing RPMs of your favorite PHP version, but documentation was easily found on Railo's site and other sites found through Google. Like Adobe's product, Railo comes with web administration tools to manage the server and application-specific settings and resources. This is a big step up from the PHP and Linux world, where you normally need to configure a lot of your application's settings (data sources for example) in configuration files. The Railo administrator goes a few steps beyond Adobe as well, and makes context specific administration consoles available, so individual applications and websites can define their own sandboxed data sources, virtual mappings, and more. This is a really nice touch, and has been a requested feature for a long time. Where Railo Shines I have already reviewed some of the reasons why Railo is impressive. Aside from being a very powerful RAD, with performance that rivals or beats Adobe, Railo distinguishes itself further with some impressive features. Virtual File systems and Mappings As developers, we have all had to deal with managing remote or compressed files at one time or another. This feature in Railo does in a few mouse clicks what takes hundreds of lines of code. Railo lets you map remote file systems, like FTP, drive shares, and even Amazon S3 buckets and assign them to a virtual path in your application! This means that you can use the simple built in functions for file manipulation, and treat those files as if they were sitting right on the local file system. The support goes even further, and lets you map Java jar files and .zip files, so you can dynamically reference and run code sitting inside compressed archives. Setting up new mappings is a point-and-click affair in the Railo administrator or can be done programmatically. Application Distribution and Source Code Security The Java world has always been a step (alright, several steps) ahead of web application developers in packaging and distribution of applications. Many developers have their own home-grown methods for deploying a site and many web development applications, like Dreamweaver, have an FTP based method of deployment. Ultimately, it usually means handing over unprotected source code. CFML development has been the same way (yes, Adobe did have a way to compile .cfm templates, but my research shows it is both clumsy to use and not very popular). Railo brings “Java world” package deployment to CFML development. You can compile a whole application to Java byte code, compress it to a jar file and deploy it on any other Railo server. Railo is even smart enough to let you map a remote jar file on an FTP site and run it as a local web application. This means you have all the tools you need to deploy web applications and not expose your source. Built in AMF Support for Flex/Flash Applications Since Adobe open-sourced their BlazeDS AMF tools, Railo has integrated them making an easy to use system that “just works” with Flash applications. Inter-Application Integration, PDF and Video Manipulation CFML already has great capability for integrating with a huge number of database systems and can be expanded to use any of the huge number of open source Java projects. Railo can be used to talk to Amazon Web Services, like EC2 and S3 for cloud computing applications. Railo also has built in features for file conversions, such as dynamically generating PDFs, and programmatic editing and format conversions of digital video. A few simple lines of code can convert your video files to different formats, extract thumbnails for web previews, and then you could have them dropped on Amazon S3 to be served from the cloud. Very cool stuff, and worth looking at some of the examples on the Railo website. As you look over code that uses these features, it looks quite simple and it is amazing that Railo makes them look like child’s play, but there is serious inter-system integration going on behind the scenes. Railo makes it so very easy to add these capabilities to any web application. Infinitely Expandable with Java As mentioned above, it is easy to invoke Java classes from within CFML pages. Since Railo itself runs in a Java container, that means that any classes or code from the Java world can be integrated and used with a Railo application. My Experience Building a Railo Project My company has used ColdFusion for several projects. One of our commercial products is built on it and was originally designed for Adobe ColdFusion. Our product does a lot of heavy lifting with databases, internationalization, document format conversions, PDF previews and a lot more. Early in 2009 we did a complete conversion of the source to be compatible with Railo. There were only minor areas where our code needed to change, and most of them were with custom Java code that we wrote that simply needed updated to compatible with Railo's Java libraries. The pleasant surprise came when we were done and noticed a significant performance increase running on Railo. Summary In summary, I have been very impressed with Railo. It is community-driven; the people at Railo are responsive and truly care about the developer community, and the product really delivers what it claims. They have provided an application development platform that is both industry compatible and innovative. I think all seasoned web application developers will be able to appreciate what Railo has to offer. I believe that such powerful integration done so easily with only a few lines of code will draw a lot of attention. This is definitely a technology you should keep an eye on.
Read more
  • 0
  • 0
  • 3243

article-image-interactive-page-regions-drupal-6-part-2
Packt
31 Mar 2010
5 min read
Save for later

Interactive Page Regions with Drupal 6: Part 2

Packt
31 Mar 2010
5 min read
Activity 3-4–Adding CAPTCHA to the Contact form These days, there's a factor of spam form completion to legitimate that seems like 10:1. To prevent that, we're going to add a CAPTCHA to the form. This activity requires that the CAPTCHA module be installed and configured. Information about this can be found at http://drupal.org/project/captcha. CAPTCHA is a means of ensuring that the author of information being submitted is a human and not a 'robot' or 'web crawler.' Sometimes the user is asked to identify characters that appear in a graphic, sometimes they must identify the object shown in an image,or complete a simple math problem, and so on. We can begin by navigating to the CAPTCHA settings page (admin/user/captcha). The page lists the contact_mail_page and contact_user_page as forms that can have CAPTCHA set for them, but neither applies in this case, since we're using a form in a block in a view. We'll enable the CAPTCHA challenge for the user from the user form itself, but here we need to turn on the admin link to do so, so check the box labeled Add CAPTCHA administration links to forms which will provide a link on the form for us as long as we're logged in as the administrator. Having saved that change, return to our form. There, find a new link that opens as shown in the following screenshot: This brings up a dialog that allows us to choose the CAPTCHA type. Choose the type that provides an easy math equation. The result is the link changing on the form, to show us that CAPTCHA will be enabled. Why can't we see the CAPTCHA challenge, though? Because admins don't have to submit to a CAPTCHA challenge, so log out and look at the form. Adding a Contact info Attachment view With our contact form complete, it's time to complete our Contact Us page. We're going to add an attachment display to the Contact Us view that will provide other contact options. Actually, we have other options available to us. We could create this display as a block, or, since our current view has no node to display and the additional contact information will be a node, we could just have it shown by the existing Page display. We'll use an Attachment display instead of a block display simply because we don't want to use one of the block regions for the output, and we're already using the Content region for a block (the form). We've chosen not to use the Page display because it's easier to theme the output with one part of the content being a separate display. Then, its content is provided in a separate variable for us, so we'll use an Attachment display. Activity 3-5–Creating the contact-us Attachment view We need to create the content for the Attachment view. We'll be using a custom content type, Location, for this. Let's create the content (node/add/location). We'll give the content a title, Guild Builders Contact Information. For the body, we'll create a <div> and put the contact information in it. This step requires the embed_gmap module. Information about this module can be found at http://drupal.org/project/embed_gmap. Next, we'll get to the field that makes this content type different, the map. The embed_gmap module takes the content of the map field and uses it to produce and embed a Google map. Enter the address in this field. We'll save the content, which is shown in the following screenshot. With our content created, we're ready to create our Attachment display. Edit our Contact us view (admin/build/views/edit/contact_us). Create a title for the view, and name it Guild Builders Contact Information, also create the header information, to appear beneath the title. The next thing to do is create an Attachment display for our view. That takes us to the View control panel. We'll start with the Filters pane. Click on the Node: Post date filter we have, and click Override, so that our changes only affect the Attachment display. Then click Remove, because we don't want this filter for our Attachment. Click the + icon to add a filter. We created a piece of content, of the Location content type. Therefore, we can create a filter to select only the Node: Type of Location, and another to specify that the node is published, in case we ever have more than one version of that content, so that only the one that is published will be selected. In the settings dialog for the filter, specify that Published should be Yes. Next, we'll specify that the Attachment be attached to the Page display. The last thing we need to do is add a small entry to our CSS file, so that our map and contact information will appear side-by-side. /* Contact-Us page settings */#contact-us-info, .field-field.map { float: left}#contact-us-info { margin-right: 1em;} And with that, and two images that show our Attachment display (which is too large to fit on the page in one image), we're done! Summary We learned what the default Contact system does, and how to add just a little pizazz with an Attachment view. We learned how to add the Contact form to a view, and used Drupal's module architecture and hook mechanism to modify that form by creating a small module. Finally, we created an Attachment view to add content to our Contact page. [ 1 | 2 ] If you have read this article you may be interested to view : Interactive Page Regions with Drupal 6: Part 1 Drupal 6: Attachment Views, Page Views, and Theming
Read more
  • 0
  • 0
  • 820