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

How-To Tutorials

7019 Articles
article-image-microsoft-office-outlook-programming-using-vsto-30-and-c-part-2
Packt
12 Oct 2009
4 min read
Save for later

Microsoft Office Outlook Programming Using VSTO 3.0 and C#: Part 2

Packt
12 Oct 2009
4 min read
Working with Appointments Before we start working with the Appointments feature in Microsoft Office Outlook 2007, let's take a look at the Microsoft Office Outlook calendar. This will help you understand the concepts of Appointments more easily, and also explain how you can utilize this functionality for your needs. The Microsoft Outlook 2007 calendar is the scheduling component of the Outlook mail management system. It is well-integrated with other Microsoft Outlook functionality such as email, contacts, appointments, and other items in. Appointments are the actions you're scheduling in your Outlook calendar, inviting other people to participate if required. You can set the status of your availability for an appointment, and you can also schedule recurring appointments. Let's create an Outlook Appointment dynamically by using VSTO objects and C# programming: Open Visual Studio 2008, to create a new Outlook 2007 Add-in template project. Select New Project. Under Office select 2007 and select Outlook 2007 Add-in template and name the project as per your requirement. The solution will be created with all of supporting files required for the development of our Outlook solution. Write the following code, which will dynamically create an Appointment item in the ThisAddIn.cs file: private void ThisAddIn_Startup(object sender, System.EventArgs e){// Outlook AppointmentItem object to compose new AppointmentOutlook.AppointmentItem PacktAppointmentItem = (Outlook.AppointmentItem)this.Application.CreateItem(Outlook.OlItemType.olAppointmentItem);// Set the subject property valuePacktAppointmentItem.Subject = "Regarding book review";// Set the location property valuePacktAppointmentItem.Location = "Meeting Hall";// Set the start datePacktAppointmentItem.Start = DateTime.Today;// Set the end datePac ktAppointmentItem.End = DateTime.Today;// Set the body property valuePacktAppointmentItem.Body = "Book review comments fromall editors";// Set the required attendee informationPacktAppointmentItem.RequiredAttendees = "vivek@vsto.com";// Set the optional attandee informationPacktAppointmentItem.OptionalAttendees = "radhika@vsto.com";// If parameter is set to false compose Appointment won't displayPacktAppointmentItem.Display(true);// To send the composed PacktAppointmentItem//((Outlook._AppointmentItem)PacktAppointmentItem).Send();} The following screenshot shows the results of adding and executing this code: The AppointmentItem object is used to create appointments dynamically. An AppointmentItem object can be used to create a meeting, a one-time appointment, or a recurring appointment. Let's perform a demonstration of how to delete a recurring appointment from your Outlook 2007 calendar, by using VSTO programming. Open Visual Studio 2008 and create a new solution, as described earlier. Write the following code, which will dynamically delete an Appointment item, inside the ThisAddIn.cs file: private void ThisAddIn_Startup(object sender, System.EventArgs e){// Reading the calendar folder through MEPIFolder objectOutlook.MAPIFolder PacktCalendarInfo = Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderCalendar);// Get the data items in the calendar folderOutlook.Items PacktCalendarDataItems = PacktCalendarInfo.Items;// Searching the Appointment items based on subjectOutlook.AppointmentItem PacktAppointmentItem =PacktCalendarDataItems["Book release"] as Outlook.AppointmentItem;// Selected appointment's recurrence informationOutlook.RecurrencePattern PacktRecPattern = PacktAppointmentItem.GetRecurrencePattern();// Loading the appointment to AppointmentItem ObjectOutlook.AppointmentItem PacktAppointmentDelete = PacktRecPattern.GetOccurrence(new DateTime(2008, 9, 28, 8, 0, 0));// Now delete using the Delete methodPacktAppointmentDelete.Delete();} Working with meetings Meetings are generally discussions amongst more than two people, during which predetermined topics are discussed. Meetings help you prepare a plan, or finalize pending work, or perform other tasks involving colleagues. In Microsoft Office Outlook, a meeting is a scheduled appointment—that is, people are invited to attend. You can set the meeting time and other options for the meeting attendees, to process the invitation. VSTO 3.0 supports the dynamic creation of meeting items for Office. Let's create a meeting invitation dynamically, by using the VSTO object model and C# programming. Open Visual Studio 2008 and create a new solution, as explained earlier. Write the following code, which will dynamically create a meeting invite item, inside the ThisAddIn.cs file: private void ThisAddIn_Startup(object sender, System.EventArgs e){// Outlook PacktMeetingItem object to compose new meeting requestOutlook.AppointmentItem PacktMeetingItem = (Outlook.AppointmentItem)this.Application.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olAppointmentItem);PacktMeetingItem.MeetingStatus = Microsoft.Office.Interop.Outlook.OlMeetingStatus.olMeeting;// Set the subject for the meetingPacktMeetingItem.Subject = "Changes in book content";// Update the body information of the meetingPacktMeetingItem.Body = "Work on the changes and update";// Start Expiry Time of the meetingPacktMeetingItem.Start = new DateTime(2008, 9, 28, 9, 0, 0);// Set the recipient informationOutlook.Recipient PacktRecipient = PacktMeetingItem.Recipients.Add("Radhika Rajagopalan");PacktRecipient.Type = (int)Outlook.OlMeetingRecipientType.olRequired;// If parameter is set to false compose MeetingItem won't displayPacktMeetingItem.Display(true);// To send the composed PacktMeetingItem//((Outlook.MeetingItem)PacktMeetingItem).Send();} As we can see in the following screenshot, a Meeting tab is created successfully after executing this program. An Outlook meeting is one of the many types of Appointments in Outlook. Meetings are internally linked with the Outlook calendar. A meeting request can be created using only the AppointmentItem object. To create and set the meeting invitation by using the AppointmentItem, you must set the MeetingStatus property to olMeeting.
Read more
  • 0
  • 0
  • 4772

article-image-securing-your-trixbox-server
Packt
12 Oct 2009
6 min read
Save for later

Securing Your trixbox Server

Packt
12 Oct 2009
6 min read
Start with a good firewall Never have your trixbox system exposed completely on the open Internet; always make sure it is behind a good firewall. While many people think that because trixbox is running on Linux, it is totally secure, Linux, like anything else, has its share of vulnerabilities, and if things are not configured properly, is fairly simple for hackers to get into. There are really good open-source firewalls available, such as pfSense, Viata, and M0n0Wall. Any access to system services, such as HTTP or SSH, should only be done via a VPN or using a pseudo-VPN such as Hamachi. The best designed security starts with being exposed to the outside world as little as possible. If we have remote extensions that cannot use VPNs, then we will be forced to leave SIP ports open, and the next step will be to secure those as well. Stopping unneeded services Since trixbox CE is basically a stock installation of CentOS Linux, very little hardening has been done to the system to secure it. This lack of security is intentional as the first level of defence should always be a good firewall. Since there will be people who still insist on putting the system in a data center with no firewall, some care will need to be taken to ensure that the system is as secure as possible. The first step is to disable any services that are running that could be potential security vulnerabilities. We can see the list of services that are used with the chkconfig –list command. [trixbox1.localdomain rules]# chkconfig --listanacron 0:off 1:off 2:on 3:on 4:on 5:on 6:offasterisk 0:off 1:off 2:off 3:off 4:off 5:off 6:offavahi-daemon 0:off 1:off 2:off 3:off 4:off 5:off 6:offavahi-dnsconfd 0:off 1:off 2:off 3:off 4:off 5:off 6:offbgpd 0:off 1:off 2:off 3:off 4:off 5:off 6:offcapi 0:off 1:off 2:off 3:off 4:off 5:off 6:offcrond 0:off 1:off 2:on 3:on 4:on 5:on 6:offdc_client 0:off 1:off 2:off 3:off 4:off 5:off 6:offdc_server 0:off 1:off 2:off 3:off 4:off 5:off 6:offdhcpd 0:off 1:off 2:off 3:off 4:off 5:off 6:offdhcrelay 0:off 1:off 2:off 3:off 4:off 5:off 6:offez-ipupdate 0:off 1:off 2:off 3:off 4:off 5:off 6:offhaldaemon 0:off 1:off 2:off 3:on 4:on 5:on 6:offhttpd 0:off 1:off 2:off 3:on 4:on 5:on 6:offip6tables 0:off 1:off 2:off 3:off 4:off 5:off 6:offiptables 0:off 1:off 2:off 3:off 4:off 5:off 6:offisdn 0:off 1:off 2:off 3:off 4:off 5:off 6:offkudzu 0:off 1:off 2:off 3:on 4:on 5:on 6:offlm_sensors 0:off 1:off 2:on 3:on 4:on 5:on 6:offlvm2-monitor 0:off 1:on 2:on 3:on 4:on 5:on 6:offmDNSResponder 0:off 1:off 2:off 3:on 4:on 5:on 6:offmcstrans 0:off 1:off 2:off 3:off 4:off 5:off 6:offmdmonitor 0:off 1:off 2:on 3:on 4:on 5:on 6:offmdmpd 0:off 1:off 2:off 3:off 4:off 5:off 6:offmemcached 0:off 1:off 2:on 3:on 4:on 5:on 6:offmessagebus 0:off 1:off 2:off 3:on 4:on 5:on 6:offmultipathd 0:off 1:off 2:off 3:off 4:off 5:off 6:offmysqld 0:off 1:off 2:off 3:on 4:on 5:on 6:offnamed 0:off 1:off 2:off 3:off 4:off 5:off 6:offnetconsole 0:off 1:off 2:off 3:off 4:off 5:off 6:offnetfs 0:off 1:off 2:off 3:on 4:on 5:on 6:offnetplugd 0:off 1:off 2:off 3:off 4:off 5:off 6:offnetwork 0:off 1:off 2:on 3:on 4:on 5:on 6:offnfs 0:off 1:off 2:off 3:off 4:off 5:off 6:offnfslock 0:off 1:off 2:off 3:on 4:on 5:on 6:offntpd 0:off 1:off 2:off 3:on 4:on 5:on 6:offospf6d 0:off 1:off 2:off 3:off 4:off 5:off 6:offospfd 0:off 1:off 2:off 3:off 4:off 5:off 6:offportmap 0:off 1:off 2:off 3:on 4:on 5:on 6:offpostfix 0:off 1:off 2:on 3:on 4:on 5:on 6:offrdisc 0:off 1:off 2:off 3:off 4:off 5:off 6:offrestorecond 0:off 1:off 2:on 3:on 4:on 5:on 6:offripd 0:off 1:off 2:off 3:off 4:off 5:off 6:offripngd 0:off 1:off 2:off 3:off 4:off 5:off 6:offrpcgssd 0:off 1:off 2:off 3:on 4:on 5:on 6:offrpcidmapd 0:off 1:off 2:off 3:on 4:on 5:on 6:offrpcsvcgssd 0:off 1:off 2:off 3:off 4:off 5:off 6:offsaslauthd 0:off 1:off 2:off 3:off 4:off 5:off 6:offsnmpd 0:off 1:off 2:off 3:off 4:off 5:off 6:offsnmptrapd 0:off 1:off 2:off 3:off 4:off 5:off 6:offsshd 0:off 1:off 2:on 3:on 4:on 5:on 6:offsyslog 0:off 1:off 2:on 3:on 4:on 5:on 6:offvsftpd 0:off 1:off 2:off 3:off 4:off 5:off 6:offxinetd 0:off 1:off 2:off 3:on 4:on 5:on 6:offzaptel 0:off 1:off 2:on 3:on 4:on 5:on 6:offzebra 0:off 1:off 2:off 3:off 4:off 5:off 6:off The highlighted lines are services that are started automatically on system startup. The following list of services is required by trixbox CE and should not be disabled: Anacron crond haldaemon httpd kudzu lm_sensors lvm2-monitor mDNSResponder mdmonitor memcached messagebus mysqld network ntpd postfix sshd syslog xinetd zaptel To disable a service, we use the command chkconfig <servicename> off. We can now turn off some of the services that are not needed: chkconfig ircd offchkconfig netfs offchkconfig nfslock offchkconfig openibd offchkconfig portmap offchkconfig restorecond offchkconfig rpcgssd offchkconfig rpcidmapd offchkconfig vsftpd off We can also stop the services immediately without having to reboot: service ircd stopservice netfs stopservice nfslock stopservice openibd stopservice portmap stopservice restorecond stopservice rpcgssd stopservice rpcidmapd stopservice vsftpd stop Securing SSH A very large misconception is that by using SSH to access your system, you are safe from outside attacks. The security of SSH access is only as good as the security you have used to secure SSH access. Far too often, we see systems that have been hacked because their root password is very simple to guess (things like password or trixbox are not safe passwords). Any dictionary word is not safe at all, and substituting numbers for letters is very poor practice as well. So, as long as SSH is exposed to the outside, it is vulnerable. The best thing to do, if you absolutely have to have SSH running on the open Internet, is to change the port number used to access SSH. This section will detail the best methods of securing your SSH connections. Create a remote login account First off, we should create a user on the system and only allow SSH connections from it. The username should be something that only you know and is not easily guessed. Here, we will create a user called trixuser and assign a password to it. The password should be something with letters, numbers, symbols, and not based on a dictionary word. Also, try to string it into a sentence making sure to use the letters, numbers, and symbols. Spaces in passwords work well too, and are hard to add in scripts that might try to break into your server. A nice and simple tool for creating hard-to-guess passwords can be found at http://www.pctools.com/guides/password/. [trixbox1.localdomain init.d]# useradd trixuser[trixbox1.localdomain init.d]# passwd trixuser Now, ensure that the new account works by using SSH to log in to the trixbox CE server with this new account. If it does not let you in, make sure the password is correct or try to reset it. If it works, continue on. Only allowing one account access to the system over SSH is a great way to lock out most brute force attacks. To do this, we need to edit the file in /etc/ssh/sshd_config and add the following to the file. AllowUsers trixuser The PermitRootLogin setting can be edited so that root can't log in over SSH. Remove the # from in front of the setting and change the yes to no. PermitRootLogin no
Read more
  • 0
  • 0
  • 4058

article-image-enhancing-user-experience-wordpress-27part-2
Packt
12 Oct 2009
7 min read
Save for later

Enhancing User Experience with WordPress 2.7(Part 2)

Packt
12 Oct 2009
7 min read
Creating a drop-down menu for your categories Do you use a lot of categories along with their sub-categories? If so, using a drop-down menu is a nice way to categorize content, especially on larger sites. However, giving a quick access to the categories or sub-categories to readers can become a pain. Over the years, the drop-down menu has become very popular on the Internet. In this recipe, I'm going to show you how to create your own drop-down menu for your WordPress blog categories. Getting ready The menu you are going to create will first list your pages, and then at last a tab called Categories will obviously list your categories. This menu is achieved only with XHTML and CSS. No JavaScript is needed (unless you want to maintain compatibility with it commonly referred to as IE6) to ensure the best SEO possible for your WordPress blog. How to do it In order to make this recipe more readable, I have divided it in 3 steps—the PHP and the HTML, the CSS, and the JavaScript for IE6 compatibility. Step 1: PHP and HTML Open the header.php file from your theme and paste the following code where you'd like your drop-down menu to be displayed: <ul id="nav" class="clearfloat"><li><a href="<?php echo get_option('home'); ?>/"class="on">Home</a></li><?php wp_list_pages('title_li='); ?><li class="cat-item"><a href="#">Categories</a><ul class="children"><?php wp_list_categories('orderby=name&title_li=');$this_category = get_category($cat);if (get_category_children($this_category->cat_ID) != "") {echo "<ul>";wp_list_categories('orderby=id&show_count=0&title_li=&use_desc_for_title=1&child_of='.$this_category->cat_ID);echo "</ul>";}?></ul></li></ul> The purpose of this code is to make a list of all our pages and subpages, as well as a last list element named Categories. When a reader hovers on one of the top-level menu, the subpages (or categories) are displayed. Step 2: The CSS Open the style.css file from your theme and paste the following styles: #nav{background:#222;font-size:1.1em;}#nav, #nav ul {list-style: none;line-height: 1;}#nav a, #nav a:hover {display: block;text-decoration: none;border:none;}#nav li {float: left;list-style:none;border-right:1px solid #a9a9a9;}#nav a, #nav a:visited {display:block;font-weight:bold;color: #f5f5f4;padding:6px 12px;}#nav a:hover, #nav a:active, .current_page_item a, #home .on {background:#000;text-decoration:none}#nav li ul {position: absolute;left: -999em;height: auto;width: 174px;border-bottom: 1px solid #a9a9a9;}#nav li li {width: 172px;border-top: 1px solid #a9a9a9;border-right: 1px solid #a9a9a9;border-left: 1px solid #a9a9a9;background: #777;}#nav li li a, #nav li li a:visited {font-weight:normal;font-size:0.9em;color:#FFF;}#nav li li a:hover, #nav li li a:active {background:#000;}#nav li:hover ul, #nav li li:hover ul, #nav li li li:hover ul, #nav li.sfhover ul, #nav li li.sfhover ul, #nav li li li.sfhover ul {left: auto;}a.main:hover {background:none;} You may have to tweak this code a bit to match up to your blog's look and feel, for example, by adjusting colors. Once you are finished, simply save the file. Step 3: Optional JavaScript I'm not going to teach you something new here since, Internet Explorer 6 is a totally obsolete, crappy, and buggy browser. Sadly, many peoples are still using it and you may want to make sure that your blog is IE6 compliant. Modern browsers as such as Safari, Firefox, Opera, and even Internet Explorer 7 will not have any problem with the :hover pseudo-class on li elements. But you guessed it, it is asking too much from the IE6. To ensure backward compatibility on your WordPress blog, create a new file and call it dropdown.js. Put this code in the dropdown.js file: <![CDATA[//><!--sfHover = function() {var sfEls = document.getElementById("nav").getElementsByTagName("LI");for (var i=0; i<sfEls.length; i++) {sfEls[i].onmouseover=function() {this.className+=" sfhover";}sfEls[i].onmouseout=function() {this.className=this.className.replace(newRegExp(" sfhoverb"), "");}}}if (window.attachEvent) window.attachEvent("onload", sfHover);//–><!]]> Save the dropdown.js file and upload it to your wp-content/themes/yourtheme directory. Open header.php and add the following line within the <head> and </head> HTML tags: <!--[if lte IE 6]><script type="text/javascript" src="<?php bloginfo('template_url');?>/dropdown.js"></script><![endif]--> That's all! Your blog now has a very professional looking drop-down menu. How it works As IE6 cannot deal with :hover pseudo-classes on <li> elements, this small piece of code automatically ads a new CSS class, named sfhover to <li> elements when they are hovered over. When the mouse goes out of the top level element, a new function is executed, using a regular expression to remove the sfhover class. There's more... Now that I have shown you're the principle of creating a drop-down menu, you can use what you have just learned to create various kinds of menus. As an example, let's see how to re-use the previous code and create a very nice horizontal drop-down menu. Creating a horizontal drop-down menu As you'll notice by observing the code, there's a lot of similar things between this code and the one that you saw earlier. Part 1: PHP and HTML Simply copy this code where you want the menu to be displayed, for example, in your header.php file: <ul id="nav2" class="clearfloat"><li><a href="<?php echo get_option('home'); ?>/"class="on">Home</a></li><?php wp_list_categories('orderby=name&exlude=181&title_li=');$this_category = get_category($cat);if (get_category_children($this_category->cat_ID) != "") {echo "<ul>";wp_list_categories('orderby=id&show_count=0&title_li=&use_desc_for_title=1&child_of='.$this_category->cat_ID);echo "</ul>";}?></ul> Part 2: The CSS In modern drop-down menus, CSS are a very important part. Indeed, in this example it is CSS that display our menus horizontally. Paste the following code in your style.css file: #nav2{background-color: #202020;display: block;font-size:1.1em;height:50px;width:100%;}#nav2, #nav2 ul {line-height: 1;list-style: none;}#nav2 a ,#nav2 a:hover{border:none;display: block;text-decoration: none;}#nav2 li {float: left;list-style:none;}#nav2 a,#nav2 a:visited {color:#109dd0;display:block;font-weight:bold;padding:6px 12px;}#nav2 a:hover, #nav2 a:active {color:#fff;text-decoration:none}#nav2 li ul {border-bottom: 1px solid #a9a9a9;height: auto;left: -999em;position: absolute;width: 900px;z-index:999;}#nav2 li li {width: auto;}#nav2 li li a,#nav2 li li a:visited {color:#109dd0;font-weight:normal;font-size:0.9em;}#nav2 li li a:hover,#nav2 li li a:active {color:#fff;}#nav2 li:hover ul, #nav2 li li:hover ul, #nav2 li li li:hover ul,#nav2 li.sfhover ul, #nav2 li li.sfhover ul, #nav2 li li li.sfhover ul {left: 30px;} Once you have added theses lines to your style.css file and saved it, your WordPress blog will feature a very cool horizontal menu for displaying your categories. Part 3: (Optional) JavaScript As usual, if you want to maintain backward compatibility with Internet Explorer 6, you'll have to use the Javascript code that you have already seen in the previous example.
Read more
  • 0
  • 0
  • 1518

article-image-mixing-aspnet-webforms-and-aspnet-mvc
Packt
12 Oct 2009
6 min read
Save for later

Mixing ASP.NET Webforms and ASP.NET MVC

Packt
12 Oct 2009
6 min read
Ever since Microsoft started working on the ASP.NET MVC framework, one of the primary concerns was the framework's ability to re-use as many features as possible from ASP.NET Webforms. In this article by Maarten Balliauw, we will see how we can mix ASP.NET Webforms and ASP.NET MVC in one application and how data is shared between both these technologies. (For more resources on .NET, see here.) Not every ASP.NET MVC web application will be built from scratch. Several projects will probably end up migrating from classic ASP.NET to ASP.NET MVC. The question of how to combine both technologies in one application arises—is it possible to combine both ASP.NET Webforms and ASP.NET MVC in one web application? Luckily, the answer is yes. Combining ASP.NET Webforms and ASP.NET MVC in one application is possible—in fact, it is quite easy. The reason for this is that the ASP.NET MVC framework has been built on top of ASP.NET. There's actually only one crucial difference: ASP.NET lives in System.Web, whereas ASP.NET MVC lives in System.Web, System.Web.Routing, System.Web.Abstractions, and System.Web.Mvc. This means that adding these assemblies as a reference in an existing ASP.NET application should give you a good start on combining the two technologies. Another advantage of the fact that ASP.NET MVC is built on top of ASP.NET is that data can be easily shared between both of these technologies. For example, the Session state object is available in both the technologies, effectively enabling data to be shared via the Session state. Plugging ASP.NET MVC into an existing ASP.NET application An ASP.NET Webforms application can become ASP.NET MVC enabled by following some simple steps. First of all, add a reference to the following three assemblies to your existing ASP.NET application: System.Web.Routing System.Web.Abstractions System.Web.Mvc After adding these assembly references, the ASP.NET MVC folder structure should be created. Because the ASP.NET MVC framework is based on some conventions (for example, controllers are located in Controllers), these conventions should be respected. Add the folder Controllers, Views, and Views | Shared to your existing ASP.NET application. The next step in enabling ASP.NET MVC in an ASP.NET Webforms application is to update the web.config file, with the following code: < ?xml version="1.0"?> <configuration> <system.web> <compilation debug="false"> <assemblies> <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </assemblies> </compilation> <pages> <namespaces> <add namespace="System.Web.Mvc"/> <add namespace="System.Web.Mvc.Ajax"/> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing"/> <add namespace="System.Linq"/> <add namespace="System.Collections.Generic"/> </namespaces> </pages> <httpModules> <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> </httpModules> </system.web> </configuration> Note that your existing ASP.NET Webforms web.config should not be replaced by the above web.config! The configured sections should be inserted into an existing web.config file in order to enable ASP.NET MVC. There's one thing left to do: configure routing. This can easily be done by adding the default ASP.NET MVC's global application class contents into an existing (or new) global application class, Global.asax. using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace MixingBothWorldsExample { public class Global : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.IgnoreRoute("{resource}.aspx/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults ); } protected void Application_Start() { RegisterRoutes(RouteTable.Routes); } } } This code registers a default ASP.NET MVC route, which will map any URL of the form /Controller/Action/Idinto a controller instance and action method. There's one difference with an ASP.NET MVC application that needs to be noted—a catch-all route is defined in order to prevent a request for ASP.NET Webforms to be routed into ASP.NET MVC. This catch-all route looks like this: routes.IgnoreRoute("{resource}.aspx/{*pathInfo}"); This is basically triggered on every request ending in .aspx. It tells the routing engine to ignore this request and leave it to ASP.NET Webforms to handle things. With the ASP.NET MVC assemblies referenced, the folder structure created, and the necessary configurations in place, we can now start adding controllers and views. Add a new controller in the Controllers folder, for example, the following simpleHomeController: using System.Web.Mvc; namespace MixingBothWorldsExample.Controllers { public class HomeController : Controller { public ActionResult Index() { ViewData["Message"] = "This is ASP.NET MVC!"; return View(); } } } The above controller will simply render a view, and pass it a message through the ViewData dictionary. This view, located in Views | Home | Index.aspx, would look like this: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MixingBothWorldsExample.Views.Home.Index" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html > <head id="Head1" runat="server"> <title></title> </head> <body> <div> <h1><%=Html.Encode(ViewData["Message"]) %></h1> </div> </body> </html> The above view renders a simple HTML page and renders the ViewData dictionary's message as the page title.
Read more
  • 0
  • 1
  • 46362

article-image-importing-structure-and-data-using-phpmyadmin
Packt
12 Oct 2009
9 min read
Save for later

Importing Structure and Data Using phpMyAdmin

Packt
12 Oct 2009
9 min read
A feature was added in version 2.11.0: an import file may contain the DELIMITER keyword. This enables phpMyAdmin to mimic the mysql command-line interpreter. The DELIMITER separator is used to delineate the part of the file containing a stored procedure, as these procedures can themselves contain semicolons. The default values for the Import interface are defined in $cfg['Import']. Before examining the actual import dialog, let's discuss some limits issues. Limits for the transfer When we import, the source file is usually on our client machine; so, it must travel to the server via HTTP. This transfer takes time and uses resources that may be limited in the web server's PHP configuration. Instead of using HTTP, we can upload our file to the server using a protocol such as FTP, as described in the Web Server Upload Directories section. This method circumvents the web server's PHP upload limits. Time limits First, let's consider the time limit. In config.inc.php, the $cfg['ExecTimeLimit'] configuration directive assigns, by default, a maximum execution time of 300 seconds (five minutes) for any phpMyAdmin script, including the scripts that process data after the file has been uploaded. A value of 0 removes the limit, and in theory, gives us infinite time to complete the import operation. If the PHP server is running in safe mode, modifying $cfg['ExecTimeLimit'] will have no effect. This is because the limits set in php.ini or in user-related web server configuration file (such as .htaccess or virtual host configuration files) take precedence over this parameter. Of course, the time it effectively takes, depends on two key factors: Web server load MySQL server load The time taken by the file, as it travels between the client and the server,does not count as execution time because the PHP script starts to execute only once the file has been received on the server. Therefore, the $cfg['ExecTimeLimit'] parameter has an impact only on the time used to process data (like decompression or sending it to the MySQL server). Other limits The system administrator can use the php.ini file or the web server's virtual host configuration file to control uploads on the server. The upload_max_filesize parameter specifies the upper limit or the maximum file size that can be uploaded via HTTP. This one is obvious, but another less obvious parameter is post_max_size. As HTTP uploading is done via the POST method, this parameter may limit our transfers. For more details about the POST method, please refer to http://en.wikipedia.org/wiki/Http#Request_methods. The memory_limit parameter is provided to avoid web server child processes from grabbing too much of the server memory—phpMyAdmin also runs as a child process. Thus, the handling of normal file uploads, especially compressed dumps, can be compromised by giving this parameter a small value. Here, no preferred value can be recommended; the value depends on the size of uploaded data. The memory limit can also be tuned via the $cfg['MemoryLimit'] parameter in config.inc.php. Finally, file uploads must be allowed by setting file_uploads to On. Otherwise, phpMyAdmin won't even show the Location of the textfile dialog. It would be useless to display this dialog, as the connection would be refused later by the PHP component of the web server. Partial imports If the file is too big, there are ways in which we can resolve the situation. If we still have access to the original data, we could use phpMyAdmin to generate smaller CSV export files, choosing the Dump n rows starting at record # n dialog. If this were not possible, we will have to use a text editor to split the file into smaller sections. Another possibility is to use the upload directory mechanism, which accesses the directory defined in $cfg['UploadDir']. This feature is explained later in this article. In recent phpMyAdmin versions, the Partial import feature can also solve this file size problem. By selecting the Allow interrupt… checkbox, the import process will interrupt itself if it detects that it is close to the time limit. We can also specify a number of queries to skip from the start, in case we successfully import a number of rows and wish to continue from that point. Temporary directory On some servers, a security feature called open_basedir can be set up in a way that impedes the upload mechanism. In this case, or for any other reason, when uploads are problematic, the $cfg['TempDir'] parameter can be set with the value of a temporary directory. This is probably a subdirectory of phpMyAdmin's main directory, into which the web server is allowed to put the uploaded file. Importing SQL files Any file containing MySQL statements can be imported via this mechanism. The dialog is available in the Database view or the Table view, via the Import subpage, or in the Query window. There is no relation between the currently selected table (here author) and the actual contents of the SQL file that will be imported. All the contents of the SQL file will be imported, and it is those contents that determine which tables or databases are affected. However, if the imported file does not contain any SQL statements to select a database, all statements in the imported file will be executed on the currently selected database. Let's try an import exercise. First, we make sure that we have a current SQL export of the book table. This export file must contain the structure and the data. Then we drop the book table—yes, really! We could also simply rename it. Now it is time to import the file back. We should be on the Import subpage, where we can see the Location of the text file dialog. We just have to hit the Browse button and choose our file. phpMyAdmin is able to detect which compression method (if any) has been applied to the file. Depending on the phpMyAdmin version, and the extensions that are available in the PHP component of the web server, there is variation in the formats that the program can decompress. However, to import successfully, phpMyAdmin must be informed of the character set of the file to be imported. The default value is utf8. However, if we know that the import file was created with another character set, we should specify it here. An SQL compatibility mode selector is available at import time. This mode should be adjusted to match the actual data that we are about to import, according to the type of the server where the data was previously exported. To start the import, we click Go. The import procedure continues and we receive a message: Import has been successfully finished, 2 queries executed. We can browse our newly-created tables to confirm the success of the import operation. The file could be imported for testing in a different database or even in a MySQL server. Importing CSV files In this section, we will examine how to import CSV files. There are two possible methods—CSV and CSV using LOAD DATA. The first method is implemented internally by phpMyAdmin and is the recommended one for its simplicity. With the second method, phpMyAdmin receives the file to be loaded, and passes it to MySQL. In theory, this method should be faster. However, it has more requirements due to MySQL itself (see the Requirements sub-section of the CSV using LOAD DATA section). Differences between SQL and CSV formats There are some differences between these two formats. The CSV file format contains data only, so we must already have an existing table in place. This table does not need to have the same structure as the original table (from which the data comes); the Column names dialog enables us to choose which columns are affected in the target table. Because the table must exist prior to the import, the CSV import dialog is available only from the Import subpage in the Table view, and not in the Database view.   Exporting a test file Before trying an import, let's generate an author.csv export file from the author table. We use the default values in the CSV export options. We can then Empty the author table—we should avoid dropping this table because we still need the table structure. CSV From the author table menu, we select Import and then CSV. We can influence the behavior of the import in a number of ways. By default, importing does not modify existing data (based on primary or unique keys). However, the Replace table data with file option instructs phpMyAdmin to use REPLACE statement instead of INSERT statement, so that existing rows are replaced with the imported data. Using Ignore duplicate rows, INSERT IGNORE statements are generated. These cause MySQL to ignore any duplicate key problems during insertion. A duplicate key from the import file does not replace existing data, and the procedure continues for the next line of CSV data. We can then specify the character that terminates each field, the character that encloses data, and the character that escapes the enclosing character. Usually this is . For example, for a double quote enclosing character, if the data field contains a double quote, it must be expressed as "some data " some other data". For Lines terminated by, recent versions of phpMyAdmin offer the auto choice, which should be tried first as it detects the end-of-line character automatically. We can also specify manually which characters terminate the lines. The usual choice is n for UNIX-based systems, rn for DOS or Windows systems, and r for Mac-based system (up to Mac OS 9). If in doubt, we can use a hexadecimal file editor on our client computer (not part of phpMyAdmin) to examine the exact codes. By default, phpMyAdmin expects a CSV file with the same number of fields and the same field order as the target table. But this can be changed by entering a comma-separated list of column names in Column names, respecting the source file format. For example, let's say our source file contains only the author ID and the author name information: "1","John Smith" "2","Maria Sunshine" We'd have to put id, name in Column names to match the source file. When we click Go, the import is executed and we get a confirmation. We might also see the actual INSERT queries generated if the total size of the file is not too big. Import has been successfully finished, 2 queries executed.INSERT INTO `author` VALUES ('1', 'John Smith', '+01 445 789-1234')# 1 row(s) affected.INSERT INTO `author` VALUES ('2', 'Maria Sunshine', '333-3333')# 1 row(s) affected.
Read more
  • 0
  • 0
  • 13349

article-image-how-add-flair-your-actions-jquery
Packt
12 Oct 2009
11 min read
Save for later

How to Add Flair to your Actions with jQuery

Packt
12 Oct 2009
11 min read
Inline CSS modification Before we jump into the nifty jQuery effects, a quick look at CSS is in order. One way of modifying a document's appearance is by defining styles for classes in a separate stylesheet and then adding or removing those classes with jQuery. Typically, this is the preferred process for injecting CSS into HTML because it respects the stylesheet's role in dealing with the presentation of a page. However, there may be times when we need to apply styles that haven't been, or can't easily be, defined in a stylesheet. Fortunately, jQuery offers the .css() method for such occasions. This method acts as both a getter and a setter. To get the value of a style property, we simply pass the name of the property as a string, like .css('backgroundColor'). Multi-word properties can be interpreted by jQuery when hyphenated, as they are in CSS notation (background-color), or camel-cased, as they are in DOM notation (backgroundColor). For setting style properties, the .css() method comes in two flavors—one that takes a single style property and its value and one that takes a map of property-value pairs: .css('property','value').css({property1: 'value1', 'property-2': 'value2'}) Experienced JavaScript developers will recognize these jQuery maps as JavaScript object literals. Numeric values do not take quotation marks while string values do. However, when using the map notation, quotation marks are not required for property names if they are written in camel-cased DOM notation. We use the .css() method the same way as using .addClass() —by chaining it to a selector and binding it to an event. To demonstrate this, we'll use the style switcher example. <div id="switcher"> <div class="label">Text Size</div> <button id="switcher-default">Default</button> <button id="switcher-large">Bigger</button> <button id="switcher-small">Smaller</button></div><div class="speech"> <p>Fourscore and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.</p></div> By linking to a stylesheet with a few basic style rules, the page can initially look like the following screenshot: In this version of the style switcher, we're using <button> elements. Clicking on the Bigger and Smaller buttons will increase or decrease the text size of <div class="speech">, while clicking on the Default button will reset <div class="speech"> to its original text size. If all we wanted were to change the font size a single time to a predetermined value, we could still use the .addClass() method. But let's suppose that now we want the text to continue increasing or decreasing incrementally each time the respective button is clicked. Although it might be possible to define a separate class for each click and iterate through them, a more straightforward approach would be to compute the new text size each time by getting the current size and increasing it by a set factor (for example, 40%). Our code will start with the $(document).ready() and $('#switcher-large').click() event handlers: $(document).ready(function() { $('#switcher-large').click(function() { });}); Next, the font size can be easily discovered by using the .css() method: $('div.speech').css('fontSize'). However, because the returned value will include a trailing 'px', we'll need to strip that part in order to perform calculations with the value. Also, when we plan to use a jQuery object more than once, it's generally a good idea to cache the selector by storing the resulting jQuery object in a variable as well. $(document).ready(function() { var $speech = $('div.speech'); $('#switcher-large').click(function() { var num = parseFloat($speech.css('fontSize'), 10); });}); The first line inside $(document).ready() now stores a variable for <div class="speech"> itself. Notice the use of a $ in the variable name, $speech. Since $ is a legal character in JavaScript variables, we can use it as a reminder that the variable is storing a jQuery object. Inside the .click() handler, we use parseFloat() to get the font size property's number only. The parseFloat() function looks at a string from left to right until it encounters a non-numeric character. The string of digits is converted into a floating-point (decimal) number. For example, it would convert the string '12' to the number 12. In addition, it strips non-numeric trailing characters from the string, so '12px' becomes 12 as well. If the string begins with a non-numeric character, parseFloat() returns NaN, which stands for Not a Number. The second argument for parseFloat() allows us to ensure that the number is interpreted as base-10 instead of octal or some other representation. All that's left to do, if we are increasing by 40%, is to multiply num by 1.4 and then set the font size by concatenating num and 'px': $(document).ready(function() { var $speech = $('div.speech'); $('#switcher-large').click(function() { var num = parseFloat($speech.css('fontSize'), 10 ); num *= 1.4; $speech.css('fontSize', num + 'px'); });}); The equation num *= 1.4 is shorthand for num = num * 1.4. We can use the same type of shorthand for the other basic mathematical operations, as well: addition, num += 1.4; subtraction, num -= 1.4; division, num /= 1.4; and modulus (division remainder), num %= 1.4. Now when a user clicks on the Bigger button, the text becomes larger. Another click, and the text becomes larger still, as shown in the following screenshot: To get the Smaller button to decrease the font size, we will divide rather than multiply —num /= 1.4. Better still, we'll combine the two into a single .click() handler on all <button> elements within <div id="switcher">. Then, after finding the numeric value, we can either multiply or divide depending on the ID of the button that was clicked. Here is what that code looks like now: $(document).ready(function() { var $speech = $('div.speech'); $('#switcher button').click(function() { var num = parseFloat( $speech.css('fontSize'), 10 ); if (this.id == 'switcher-large') { num *= 1.4; } else if (this.id == 'switcher-small') { num /= 1.4; } $speech.css('fontSize', num + 'px); });}); We can access the id property of the DOM element referred to by this, which appears here inside the if and else if statements. Here, it is more efficient to use this than to create a jQuery object just to test the value of a property. It's also nice to have a way to return the font size to its initial value. To allow the user to do so, we can simply store the font size in a variable immediately when the DOM is ready. We can then use this value whenever the Default button is clicked. To handle this click, we could add another else if statement. However, perhaps a switch statement would be more appropriate. $(document).ready(function() { var $speech = $('div.speech'); var defaultSize = $speech.css('fontSize'); $('#switcher button').click(function() { var num = parseFloat( $speech.css('fontSize'), 10 ); switch (this.id) { case 'switcher-large': num *= 1.4; break; case 'switcher-small': num /= 1.4; break; default: num = parseFloat(defaultSize, 10); } $speech.css('fontSize', num + 'px'); });}); Here we're still checking the value of this.id and changing the font size based on it, but if its value is neither 'switcher-large' nor 'switcher-small' it will default to the initial font size. Basic hide and show The basic .hide() and .show() methods, without any parameters, can be thought of as smart shorthand methods for .css('display','string'), where 'string' is the appropriate display value. The effect, as might be expected, is that the matched set of elements will be immediately hidden or shown, with no animation. The .hide() method sets the inline style attribute of the matched set of elements to display:none. The smart part here is that it remembers the value of the display property—typically block or inline—before it was changed to none. Conversely, the .show() method restores the matched set of elements to whatever visible display property they had before display:none was applied. For more information about the display property and how its values are visually represented in a web page, visit the Mozilla Developer Center at https://developer.mozilla.org/en/CSS/display/ and view examples at https://developer.mozilla.org/samples/cssref/display.html. This feature of .show() and .hide() is especially helpful when hiding elements whose default display property is overridden in a stylesheet. For example, the <li> element has the property display:block by default, but we might want to change it to display:inline for a horizontal menu. Fortunately, using the .show() method on a hidden element such as one of these <li> tags would not merely reset it to its default display:block, because that would put the <li> on its own line. Instead, the element is restored to its previous display:inline state, thus preserving the horizontal design. A quick demonstration of these two methods can be set up by adding a second paragraph and a "read more" link after the first paragraph in the example HTML: <div id="switcher"> <div class="label">Text Size</div> <button id="switcher-default">Default</button> <button id="switcher-large">Bigger</button> <button id="switcher-small">Smaller</button></div><div class="speech"> <p>Fourscore and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal. </p> <p>Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battlefield of that war. We have come to dedicate a portion of that field as a final resting-place for those who here gave their lives that the nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we cannot dedicate, we cannot consecrate, we cannot hallow, this ground. </p> <a href="#" class="more">read more</a></div> When the DOM is ready, the second paragraph is hidden: $(document).ready(function() { $('p:eq(1)').hide(); }); And the speech looks like the following screenshot: Then, when the user clicks on read more at the end of the first paragraph, that link is hidden and the second paragraph is shown: $(document).ready(function() { $('p:eq(1)').hide(); $('a.more').click(function() { $('p:eq(1)').show(); $(this).hide(); return false; });}); Note the use of return false to keep the link from activating its default action. Now the speech looks like this: The .hide() and .show() methods are quick and useful, but they aren't very flashy. To add some flair, we can give them a speed. Effects and speed When we include a speed (or, more precisely, a duration) with .show() or .hide(), it becomes animated—occurring over a specified period of time. The .hide('speed') method, for example, decreases an element's height, width, and opacity simultaneously until all three reach zero, at which point the CSS rule display:none is applied. The .show('speed') method will increase the element's height from top to bottom, width from left to right, and opacity from 0 to 1 until its contents are completely visible. Speeding in With any jQuery effect, we can use one of three preset speeds: 'slow', 'normal', and 'fast'. Using .show('slow') makes the show effect complete in .6 seconds, .show('normal') in .4 seconds, and .show('fast') in .2 seconds. For even greater precision we can specify a number of milliseconds, for example .show(850). Unlike the speed names, the numbers are not wrapped in quotation marks. Let's include a speed in our example when showing the second paragraph of Lincoln's Gettysburg Address: $(document).ready(function() { $('p:eq(1)').hide(); $('a.more').click(function() { $('p:eq(1)').show('slow'); $(this).hide(); return false; });}); When we capture the paragraph's appearance at roughly halfway through the effect, we see something like the following: Fading in and fading out While the animated .show() and .hide() methods are certainly flashy, they may at times be too much of a good thing. Fortunately, jQuery offers a couple other pre-built animations for a more subtle effect. For example, to have the whole paragraph appear just by gradually increasing the opacity, we can use .fadeIn('slow') instead: $(document).ready(function() { $('p:eq(1)').hide(); $('a.more').click(function() { $('p:eq(1)').fadeIn('slow'); $(this).hide(); return false; });}); This time when we capture the paragraph's appearance halfway, it's seen as: The difference here is that the .fadeIn() effect starts by setting the dimensions of the paragraph so that the contents can simply fade into it. To gradually decrease the opacity we can use .fadeOut().
Read more
  • 0
  • 0
  • 4206
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-customizing-and-extending-aspnet-mvc-framework
Packt
12 Oct 2009
5 min read
Save for later

Customizing and Extending the ASP.NET MVC Framework

Packt
12 Oct 2009
5 min read
(For more resources on .NET, see here.) Creating a control When building applications, you probably also build controls. Controls are re-usable components that contain functionality that can be re-used in different locations. In ASP.NET Webforms, a control is much like an ASP.NET web page. You can add existing web server controls and markup to a custom control and define properties and methods for it. When, for example, a button on the control is clicked, the page is posted back to the server that performs the actions required by the control. The ASP.NET MVC framework does not support ViewState and postbacks, and therefore, cannot handle events that occur in the control. In ASP.NET MVC, controls are mainly re-usable portions of a view, called partial views, which can be used to display static HTML and generated content, based on ViewData received from a controller. In this topic, we will create a control to display employee details. We will start by creating a new ASP.NET MVC application using File | New | Project... in Visual Studio, and selecting ASP.NET MVC Application under Visual C# - Web. First of all, we will create a new Employee class inside the Models folder. The code for this Employee class is: public class Employee{ public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public string Department { get; set; }} On the home page of our web application, we will list all of our employees. In order to do this, modify the Index action method of the HomeController to pass a list of employees to the view in the ViewData dictionary. Here's an example that creates a list of two employees and passes it to the view: public ActionResult Index(){ ViewData["Title"] = "Home Page"; ViewData["Message"] = "Our employees welcome you to our site!"; List<Employee> employees = new List<Employee> { new Employee{ FirstName = "Maarten", LastName = "Balliauw", Email = "maarten@maartenballiauw.be", Department = "Development" }, new Employee{ FirstName = "John", LastName = "Kimble", Email = "john@example.com", Department = "Development" } }; return View(employees);} The corresponding view, Index.aspx in the Views | Home folder of our ASP.NET MVC application, should be modified to accept a List<Employee> as a model. To do this, edit the code behind the Index.aspx.cs file and modify its contents as follows: using System.Collections.Generic;using System.Web.Mvc;using ControlExample.Models;namespace ControlExample.Views.Home{ public partial class Index : ViewPage<List<Employee>> { }} In the Index.aspx view, we can now use this list of employees. Because we will display details of more than one employee somewhere else in our ASP.NET MVC web application, let's make this a partial view. Right-click the Views | Shared folder, click on Add | New Item... and select the MVC View User Control item template under Visual C# | Web | MVC. Name the partial view, DisplayEmployee.ascx. The ASP.NET MVC framework provides the flexibility to use a strong-typed version of the ViewUserControl class, just as the ViewPage class does. The key difference between ViewUserControl and ViewUserControl<T>is that with the latter, the type of view data is explicitly passed in, whereas the non-generic version will contain only a dictionary of objects. Because the DisplayEmployee.aspx partial view will be used to render items of the type Employee, we can modify the DisplayEmployee. ascx code behind the file DisplayEmployee.ascx.cs and make it strong-typed: using ControlExample.Models;namespace ControlExample.Views.Shared{ public partial class DisplayEmployee : System.Web.Mvc.ViewUserControl<Employee> { }} In the view markup of our partial view, the model can now be easily referenced. Just as with a regular ViewPage, the ViewUserControl will have a ViewData property containing a Model property of the type Employee. Add the following code to DisplayEmployee.ascx: <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="DisplayEmployee.ascx.cs" Inheits="ControlExample.Views.Shared.DisplayEmployee" %><%=Html.Encode(Model.LastName)%>, <%=Html.Encode(Model.FirstName)%><br/><em><%=Html.Encode(Model.Department)%></em> The control can now be used on any view or control in the application. In the Views | Home | Index.aspx view, use the Model property (which is a List<Employee>) and render the control that we have just created for each employee: <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs"Inherits="ControlExample.Views.Home.Index" %><asp:Content ID="indexContent" ContentPlaceHolderID="MainContent"runat="server"> <h2><%= Html.Encode(ViewData["Message"]) %></h2> <p>Here are our employees:</p> <ul> <% foreach (var employee inModel) { %> <li> <% Html.RenderPartial("DisplayEmployee", employee); %> </li> <% } %> </ul></asp:Content> In case the control's ViewData type is equal to the view page's ViewData type, another method of rendering can also be used. This method is similar to ASP.NET Webforms controls, and allows you to specify a control as a tag. Optionally, a ViewDataKey can be specified. The control will then fetch its data from the ViewData dictionary entry having this key. <uc1:EmployeeDetails ID="EmployeeDetails1" runat="server" ViewDataKey="...." /> For example, if the ViewData contains a key emp that is filled with an Employee instance, the user control could be rendered using the following markup: <uc1:EmployeeDetails ID="EmployeeDetails1" runat="server" ViewDataKey="emp" /> After running the ASP.NET MVC web application, the result will appear as shown in the following screenshot:
Read more
  • 0
  • 0
  • 6993

article-image-testing-your-business-rules-jboss-drools
Packt
12 Oct 2009
9 min read
Save for later

Testing your Business Rules in JBoss Drools

Packt
12 Oct 2009
9 min read
When we start writing 'real' business rules, there is very little space to make mistakes as the mistakes made can cause a lot of wastage of money. How much money would a company lose if a rule that you wrote gave double the intended discount to a customer? Or, what if your airline ticket pricing rule started giving away first class transatlantic flights for one cent? Of course, mistakes happen. This article makes sure that these costly mistakes don't happen to you. If you're going through the trouble of writing business rules, you will want to make sure that they do what you intend them to, and keep on doing what you intend, even when you or other people make changes, both now and in the future. But first of all, we will see how testing is not a standalone activity, but part of an ongoing cycle. Testing when building rules It's a slightly morbid thought, but there's every chance that some of the business rules that you write will last longer than you do. Remember the millennium bug caused by programmers in the 1960's, assuming that nobody would be using their work in 40 years' time, and then being surprised when the year 2000 actually came along? Rather than 'play and throw away', we're more likely to create production business rules in the following cycle: Write your rules (or modify an existing one) based on a specification, or feedback from end users. Test your rules to make sure that your new rules do what you want them to do, and ensure that you haven't inadvertently broken any existing rules. Deploy your rules to somewhere other than your local machine, where end users (perhaps via a web page or an enterprise system) can interact with them. You can repeat steps 1, 2, and 3 as often as required. That means, repeat as many times as it takes you to get the first version into production. Or, deploy now and modify it anytime later –in 1, 2, or 10 years time. Making testing interesting Normal testing, where you inspect everything manually, is booooooooring! You might check everything the first time, but after the hundredth deployment you'll be tempted to skip your tests—and you'll probably get away with it without any problems. You'll then be tempted to skip your tests on the 101st deployment—still no problems. So, not testing becomes a bad habit either because you're bored, or because your boss fails to see the value of the tests. The problem, then comes one Friday afternoon, or just when you're about to go on vacation, or some other worst possible time. The whole world will see any mistakes in the rules that are in production. Therefore, fixing them is a lot more time and money consuming than if you catch the error at the very start on your own PC. What's the solution? Automate the testing. All of your manual checks are very repetitive—exactly the sort of thing that computers are good at. The sort of checks for our chocolate shipment example would be 'every time we have an order of 2000 candy bars, we should have 10 shipments of 210 bars and one shipment of 110 bars'. Testing using Guvnor There is one very important  advantage of testing—we can instantly see whether our tests are correct, without having to wait for our rules to be deployed into the target system. At a high level, Guvnor has two main screens that deal with testing: An individual test screen: Here you can edit your test by specifying the values that you want to input, and the values that you expect once your rules have fired A package or multiple tests screen (below): This allows you to run (later on) all of the tests in your package, to catch any rules that you may have inadvertently broken Another way of saying this is: You write your tests for selfish reasons because you need them to ensure that your rules do what you want them to do. By keeping your tests for later, they automatically become a free safety net that catches bugs as soon as you make a change. Testing using FIT Guvnor testing is great. But, often, a lot of what you are testing for is already specified in the requirements documents for the system. With a bit of thought in specifying various scenarios in your requirements documents, FIT allows you to automatically compare these requirements against your rules. These requirements documents can be written in Microsoft Word, or similar format, and they will highlight if the outputs aren't what is specified. Like Drools, FIT is an open source project, so there is no charge for either using it, or for customizing it to fit your needs. Before you get too excited about this, your requirements documents do have some compromises. The tests must specify the values to be input to the rules, and the expected result—similar to the examples, or scenarios, that many specifications already contain. These scenarios have to follow a FIT-specific format. Specification documents should follow a standard format anyway—the FIT scenario piece is often less than 10% of it, and it is still highly human-readable! Even better, the document can be written in anything that generates HTML, which includes Microsoft Word, Excel, OpenOffice, Google documents, and most of the myriad of editors that are available today. Like the Guvnor testing, we can use FIT to test whether our individual requirements are being met when writing our rules. It is possible to run FIT automatically over multiple requirement documents to ensure that nothing has 'accidentally' broken as we update other rules. Getting FIT When you download the samples, you will probably notice three strange packages and folders. fit-testcase: This folder resides just within the main project folder, and contains the FIT requirements documents that we're going to test against. chap7: This is a folder under src/main/java/net/firstpartners, and contains the startpoint (FitRulesExample.java) that we'll use to kick-start our FIT Tests. FIT: This folder is next to the chap7 folder. It folder contains some of the 'magic plumbing' that makes FIT work. Most business users won't care how this works (you probably won't need to change what you find here), but we will take a look at it in more detail in case we want to customize exactly how FIT works. If you built the previous example using Maven, then all of the required FIT software will have been downloaded for you. (Isn't Maven great?) So, we're ready to go. The FIT requirements document Open the word document fit-testcase.doc using Word, or OpenOffice. Remember that it's in the fit-testcase folder. fit-testcase.doc is a normal document, without any hidden code. The testing magic lies in the way the document is laid out. More specifically, it's in the tables that you see in the document. All of the other text is optional. Let's go through it. Logo and the first paragraph At the very top of the document is the Drools logo and a reference to where you can download FIT for rules code. It's also worth reading the text here, as it's another explanation of what the FIT project does and how it works. None of this text matters, or rather FIT ignores it as it contains no tables. We can safely replace this (or any other text in this document that isn't in the table) with your company logo, or whatever you normally put at the top of your requirement documents. FIT is a GPL (General Public License) open source software. This means you can modify it (as long as you publish your changes). In this sample we've modified it to accept global variables passed into the rules. (We will use this feature in step 3.) The changes are published in the FIT plumbing directory, which is a part of the sample. Feel free to use it in your own projects. First step—setup The setup table prepares the ground for our test, and explains the objects that we want to use in our test. These objects are familiar as they are the Java facts that we've used in our rules. There's a bit of text (worth reading as it also explains what the table does), but FIT ignores it. The bit that it reads is given in the following table: net.firstpartners.fit.fixture.Setup net.firstpartners.chap6.domain.CustomerOrder AcmeOrder net.firstpartners.chap6.domain.OoompaLoompaDate nextAvailableShipmentDate If you're wondering what this does, try the following explanation in the same table format: Use the piece of plumbing called 'Setup'   Create CustomerOrder and call it AcmeOrder Create OoompaLoompaDate and call it nextAvailableShipmentDate There is nothing here that we haven't seen before. Note that we will be passing nextShipmentDate as a global so that it matches the global of a same name in our rules file (the match includes the exact spelling, and the same lower-and uppercase). Second step—values in The second part also has the usual text explanation (ignored by FIT) and table (the important bit), which explains how to set the values. net.firstpartners.fit.fixture.Populate AcmeOrder Set initial balance 2000 AcmeOrder Set current balance 2000 It's a little bit clearer than the first table, but we'll explain it again anyway. Use the piece of plumbing called Populate AcmeOrder Take the ... we created earlier, and set it to have an initial balance of ... 2000 AcmeOrder Take the ... we created earlier, and set it to have a current balance of ... 2000 Third step—click on the Go button Our next part starts the rules. Or rather, the table tells FIT to invoke the rules. The rest of the text (which is useful to explain what is going on to us humans) gets ignored. net.firstpartners.fit.fixture.Engine Ruleset src/main/java/net/firstpartners/chap6/shipping-rules.drl Assert AcmeOrder Global nextAvailableShipmentDate Execute   The following table is the same again, in English: Use the piece of plumbing called 'Engine' Ruleset Use the rules in shipping-rules.drl Assert Pass our AcmeOrder to the rule engine (as a fact) Global Pass our nextAvailableShipmentDate to the rule engine (as a global) Execute Click on the Go Button
Read more
  • 0
  • 0
  • 8006

article-image-documenting-your-python-project-part2
Packt
12 Oct 2009
11 min read
Save for later

Documenting Your Python Project-part2

Packt
12 Oct 2009
11 min read
Building the Documentation An easier way to guide your readers and your writers is to provide each one of them with helpers and guidelines, as we have learned in the previous section of this article. From a writer's point of view, this is done by having a set of reusable templates together with a guide that describes how and when to use them in a project. It is called a documentation portfolio. From a reader point of view, being able to browse the documentation with no pain, and getting used to finding the info efficiently, is done by building a document landscape. Building the Portfolio There are many kinds of documents a software project can have, from low-level documents that refer directly to the code, to design papers that provide a high-level overview of the application. For instance, Scott Ambler defines an extensive list of document types in his book Agile Modeling (http://www.agilemodeling.com/essays/agileArchitecture.htm). He builds a portfolio from early specifications to operations documents. Even the project management documents are covered, so the whole documenting needs are built with a standardized set of templates. Since a complete portfolio is tightly related to the methodologies used to build the software, this article will only focus on a common subset that you can complete with your specific needs. Building an efficient portfolio takes a long time, as it captures your working habits. A common set of documents in software projects can be classified in three categories: Design: All documents that provide architectural information, and low-level design information, such as class diagrams, or database diagrams Usage: Documents on how to use the software; this can be in the shape of a cookbook and tutorials, or a module-level help Operations: Provide guidelines on how to deploy, upgrade, or operate the software Design The purpose of design documentation is to describe how the software works and how the code is organized. It is used by developers to understand the system but is also a good entry point for people who are trying to understand how the application works. The different kinds of design documents a software can have are: Architecture overview Database models Class diagrams with dependencies and hierarchy relations User interface wireframes Infrastructure description Mostly, these documents are composed of some diagrams and a minimum amount of text. The conventions used for the diagrams are very specific to the team and the project, and this is perfectly fine as long as it is consistent. UML provides thirteen diagrams that cover most aspects in a software design. The class diagram is probably the most used one, but it is possible to describe every aspect of software with it. See http://en.wikipedia.org/wiki/Unified_Modeling_Language#Diagrams. Following a specific modeling language such as UML is not often fully done, and teams just make up their own way throughout their common experience. They pick up good practice from UML or other modeling languages, and create their own recipes. For instance, for architecture overview diagrams, some designers just draw boxes and arrows on a whiteboard without following any particular design rules and take a picture of it. Others work with simple drawing programs such as Dia (http://www.gnome.org/projects/dia) or Microsoft Visio (not open source, so not free), since it is enough to understand the design. Database model diagrams depend on the kind of database you are using. There are complete data modeling software applications that provide drawing tools to automatically generate tables and their relations. But this is overkill in Python most of the time. If you are using an ORM such as SQLAlchemy (for instance), simple boxes with lists of fields, together with table relations are enough to describe your mappings before you start to write them. Class diagrams are often simplified UML class diagrams: There is no need in Python to specify the protected members of a class, for instance. So the tools used for an architectural overview diagram fit this need too. User interface diagrams depend on whether you are writing a web or a desktop application. Web applications often describe the center of the screen, since the header, footer, left, and right panels are common. Many web developers just handwrite those screens and capture them with a camera or a scanner. Others create prototypes in HTML and make screen snapshots. For desktop applications, snapshots on prototype screens, or annotated mock-ups made with tools such as Gimp or Photoshop are the most common way. Infrastructure overview diagrams are like architecture diagrams, but they focus on how the software interacts with third-party elements, such as mail servers, databases, or any kind of data streams. Common Template The important point when creating such documents is to make sure the target readership is perfectly known, and the content scope is limited. So a generic template for design documents can provide a light structure with a little advice for the writer. Such a structure can include: Title Author Tags (keywords) Description (abstract) Target (Who should read this?) Content (with diagrams) References to other documents The content should be three or four screens (a 1024x768 average screen) at the most, to be sure to limit the scope. If it gets bigger, it should be split into several documents or summarized. The template also provides the author's name and a list of tags to manage its evolutions and ease its classification. This will be covered later in the article. Paster is the right tool to use to provide templates for documentation. pbp.skels implements the design template described, and can be used exactly like code generation. A target folder is provided and a few questions are answered: $ paster create -t pbp_design_doc designSelected and implied templates:pbp.skels#pbp_design_doc A Design documentVariables:egg: designpackage: designproject: designEnter title ['Title']: Database specifications for atomisator.dbEnter short_name ['recipe']: mappersEnter author (Author name) ['John Doe']: TarekEnter keywords ['tag1 tag2']: database mapping sqlCreating template pbp_design_docCreating directory ./designCopying +short_name+.txt_tmpl to ./design/mappers.txt The result can then be completed: =========================================Database specifications for atomisator.db=========================================:Author: Tarek:Tags: database mapping sql:abstract:Write here a small abstract about your design document... contents ::Who should read this ?::::::::::::::::::::::Explain here who is the target readership.Content:::::::Write your document here. Do not hesitate to split it in severalsections.References::::::::::Put here references, and links to other documents. Usage Usage documentation describes how a particular part of the software works. This documentation can describe low-level parts such as how a function works, but also high-level parts such command-line arguments for calling the program. This is the most important part of documentation in framework applications, since the target readership is mainly the developers that are going to reuse the code. The three main kinds of documents are: Recipe: A short document that explains how to do something. This kind of document targets one readership and focuses on one specific topic. Tutorial: A step-by-step document that explains how to use a feature of the software. This document can refer to recipes, and each instance is intended to one readership. Module helper: A low-level document that explains what a module contains. This document could be shown (for instance) when you call the help built-in over a module. Recipe A recipe answers a very specific problem and provides a solution to resolve it. For example, ActiveState provides a Python Cookbook online (a cookbook is a collection of recipes), where developers can describe how to do something in Python (http://aspn.activestate.com/ASPN/Python/Cookbook). These recipes must be short and are structured like this: Title Submitter Last updated Version Category Description Source (the source code) Discussion (the text explaining the code) Comments (from the web) Often, they are one-screen long and do not go into great details. This structure perfectly fits a software's needs and can be adapted in a generic structure, where the target readership is added and the category replaced by tags: Title (short sentence) Author Tags (keywords) Who should read this? Prerequisites (other documents to read, for example) Problem (a short description) Solution (the main text, one or two screens) References (links to other documents) The date and version are not useful here, since we will see later that the documentation is managed like source code in the project. Like the design template, pbp.skels provide a pbp_recipe_doc template that can be used to generate this structure: $ paster create -t pbp_recipe_doc recipesSelected and implied templates:pbp.skels#pbp_recipe_doc A recipeVariables:egg: recipespackage: recipesproject: recipesEnter title (use a short question): How to use atomisator.dbEnter short_name ['recipe'] : atomisator-dbEnter author (Author name) ['John Doe']: TarekEnter keywords ['tag1 tag2']: atomisator dbCreating template pbp_recipe_docCreating directory ./recipesCopying +short_name+.txt_tmpl to ./recipes/atomisator-db.txt The result can then be completed by the writer: ========================How to use atomisator.db========================:Author: Tarek:Tags: atomisator db.. contents ::Who should read this ?::::::::::::::::::::::Explain here who is the target readership.Prerequisites:::::::::::::Put here the prerequisites for people to follow this recipe.Problem:::::::Explain here the problem resolved in a few sentences.Solution::::::::Put here the solution.References::::::::::Put here references, and links to other recipes. Tutorial A tutorial differs from a recipe in its purpose. It is not intended to resolve an isolated problem, but rather describes how to use a feature of the application step by step. This can be longer than a recipe and can concern many parts of the application. For example, Django provides a list of tutorials on its website. Writing your first Django App, part 1 (http://www.djangoproject.com/documentation/tutorial01) explains in ten screens how to build an application with Django. A structure for such a document can be: Title (short sentence) Author Tags (words) Description (abstract) Who should read this? Prerequisites (other documents to read, for example) Tutorial (the main text) References (links to other documents) The pbp_tutorial_doc template is provided in pbp.skels as well with this structure, which is similar to the design template. Module Helper The last template that can be added in our collection is the module helper template. A module helper refers to a single module and provides a description of its contents, together with usage examples. Some tools can automatically build such documents by extracting the docstrings and computing module help using pydoc, like Epydoc ( http://epydoc.sourceforge.net). So it is possible to generate an extensive documentation based on API introspection. This kind of documentation is often provided in Python frameworks. For instance Plone provides an http://api.plone.org server that keeps an up-to-date collection of module helpers. The main problems with this approach are: There is no smart selection performed over the modules that are really interesting to document. The code can be obfuscated by the documentation. Furthermore, module documentation provides examples that sometimes refer to several parts of the module, and are hard to split between the functions' and classes' docstrings. The module docstring could be used for that purpose by writing a text at the top of the module. But this ends in having a hybrid file composed of a block of text, then a block of code. This is rather obfuscating when the code represents less than 50% of the total length. If you are the author, this is perfectly fine. But when people try to read the code (not the documentation), they will have to jump the docstrings part. Another approach is to separate the text in its own file. A manual selection can then be operated to decide which Python module will have its module helper file. The documents can then be separated from the code base and allowed to live their own life, as we will see in the next part. This is how Python is documented. Many developers will disagree on the fact that doc and code separation is better than docstrings. This approach means that the documentation process is fully integrated in the development cycle; otherwise it will quickly become obsolete. The docstrings approach solves this problem by providing proximity between the code and its usage example, but doesn't bring it to a higher level: a document that can be used as part of a plain documentation. The template for Module Helper is really simple, as it contains just a little metadata before the content is written. The target is not defined since it is the developers who wish to use the module: Title (module name) Author Tags (words) Content
Read more
  • 0
  • 0
  • 7658

article-image-php-magic-features
Packt
12 Oct 2009
5 min read
Save for later

PHP Magic Features

Packt
12 Oct 2009
5 min read
In this article by Jani Hartikainen, we'll look at PHP's "magic" features: Magic methods, which are class methods with specific names, are used to perform various specialized tasks. They are grouped into two: overloading methods and non-overloading methods. Overloading magic methods are used when your code attempts to access a method or a property which does not exist. Non-overloading methods perform other tasks. Magic functions, which are similar to magic methods, but are just plain functions outside any class. Currently there is only one magic function in PHP. Magic constants, which are similar to constants in notation, but act more like "dynamic" constants - their value depends on where you use them. We'll also look at some practical examples of using some of these, and lastly we'll check out what new features PHP 5.3 is going to add. Magic methods For starters, let's take a look at the magic methods PHP provides. We will first go over the non-overloading methods. __construct and __destruct class SomeClass { public function __construct() { } public function __destruct() { }} The most common magic method in PHP is __construct. In fact, you might not even have thought of it as a magic method at all, as it's so common.  __construct is the class constructor method, which gets called when you instantiate a new object using the new keyword, and any parameters used will get passed to __construct. $obj = new SomeClass(); __destruct is __construct's "pair". It is a class destructor, which is rarely used in PHP, but still it is good to know about  its existence. It gets called when your object falls out of scope or is garbage collected. function someFunc() { $obj = new SomeClass(); //when the function ends, $obj falls out of scope and SomeClass __destruct is called } someFunc(); If you make the constructor private or protected, it means that the class cannot be instantiated, except inside a method of the same class. You can use this to your advantage, for example to create a singleton. __clone class SomeClass { public $someValue; public function __clone() { $clone = new SomeClass(); $clone->someValue = $this->someValue; return $clone; }} The __clone method is called when you use PHP's clone keyword, and is used to create a clone of the object. The purpose is that by implementing __clone, you can define a way to copy objects. $obj1 = new SomeClass();$obj1->someValue = 1;$obj2 = clone $obj1;echo $obj2->someValue;//echos 1 Important: __clone is not the same as =. If you use = to assign an object to another variable, the other variable will still refer to the same object as the first one! If you use the clone keyword, the purpose is to return a new object with similar state as the original. Consider the following: $obj1 = new SomeClass();$obj1->someValue = 1;$obj2 = $obj1;$obj3 = clone $obj1;$obj1->someValue = 2; What are the values of the someValue property in $obj2 and $obj3 now? As we have used the assign operator to create $obj2, it refers to the same object as $obj1, thus $obj2->someValue is 2. When creating $obj3, we have used the clone keyword, so the __clone method was called. As __clone creates a new instance, $obj3->someValue is still the same as it was when we cloned $obj1: 1. If you want to disable cloning, you can make __clone private or protected. __toString class SomeClass { public function __toString() { return 'someclass'; }} The __toString method is called when PHP needs to convert class instances into strings, for example when echoing: $obj = new SomeClass();echo $obj;//will output 'someclass' This can be a useful example to help you identify objects or when creating lists. If we have a user object, we could define a __toString method which outputs the user's first and last names, and when we want to create a list of users, we could simply echo the objects themselves. __sleep and __wakeup class SomeClass { private $_someVar; public function __sleep() { return array('_someVar'); } public function __wakeup() { }} These two methods are used with PHP's serializer: __sleep is called with serialize(), __wakeup is called with unserialize(). Note that you will need to return an array of the class variables you want to save from __sleep. That's why the example class returns an array with _someVar in it: Without it, the variable will not get serialized. $obj = new SomeClass();$serialized = serialize($obj);//__sleep was calledunserialize($serialized);//__wakeup was called You typically won't need to implement __sleep and __wakeup, as the default implementation will serialize classes correctly. However, in some special cases it can be useful. For example, if your class stores a reference to a PDO object, you will need to implement __sleep, as PDO objects cannot be serialized. As with most other methods, you can make __sleep private or protected to stop serialization. Alternatively, you can throw an exception, which may be a better idea as you can provide a more meaningful error message. An alternative to __sleep and __wakeup is the Serializable interface. However, as its behavior is different from these two methods, the interface is outside the scope of this article. You can find info on it in the PHP manual. __set_state class SomeClass { public $someVar; public static function __set_state($state) { $obj = new SomeClass(); $obj->someVar = $state['someVar']; return $obj; }} This method is called in code created by var_export. It gets an array as its parameter, which contains a key and value for each of the class variables, and it must return an instance of the class. $obj = new SomeClass();$obj->someVar = 'my value';var_export($obj); This code will output something along the lines of: SomeClass::__set_state(array('someVar'=>'my value')); Note that var_export will also export private and protected variables of the class, so they too will be in the array.
Read more
  • 0
  • 0
  • 3314
article-image-support-developers-spring-web-flow-2
Packt
12 Oct 2009
9 min read
Save for later

Support for Developers of Spring Web Flow 2

Packt
12 Oct 2009
9 min read
Build systems Build systems are not necessary for building web applications with Spring Web Flow, but they greatly assist a developer by resolving dependencies between packages and automating the build process. In this article, we will show you how to build your projects with Apache Ant and Apache Maven. Ant Ant is a powerful and very flexible build tool. You can write Extensible Markup Language (XML) files, which tell Ant how to build your application, where to find your dependencies, and where to copy the compiled files. Often, you won't find the need to download Ant, as it is already built-in into popular IDEs such as Eclipse and NetBeans. Ant does not provide you with an automatic dependency resolving mechanism. So you will have to manually download all the libraries your application needs. Alternatively, you can use a third-party dependency resolving system such as Apache Ivy, which we will describe later in this article. When you have obtained a copy of Ant, you can write a build.xml file as shown in the following code. <?xml version="1.0" encoding="UTF-8"?> <project name="login.flow" default="compile"> <description> login.flow </description> <property file="loginflow.properties"/> <path id="classpath"> <fileset dir="lib/"> <include name="*.jar" /> </fileset> </path> <target name="init"> <mkdir dir="${build}" /> <mkdir dir="${build}/WEB-INF/classes" /> </target> <target name="assemble-webapp" depends="init"> <copy todir="${build}" overwrite="y"> <fileset dir="${webapp-src}"> <include name="**/*/" /> </fileset> </copy> </target> <target name="compile" depends="assemble-webapp"> <javac srcdir="${src}" destdir="${build}/WEB-INF/classes"> <classpath refid="classpath" /> </javac> <echo>Copying resources</echo> <copy todir="${build}/WEB-INF/classes" overwrite="y"> <fileset dir="${resources}"> <include name="**/*/" /> </fileset> </copy> <echo>Copying libs</echo> <copy todir="${build}/WEB-INF/lib" overwrite="y"> <fileset dir="lib/"> <include name="*.jar" /> </fileset> </copy> </target> </project> First of all, we will specify that we have defined a few required folders in an external PROPERTIES file. The loginflow.properties, stored in your project's root folder, looks like this: src = src/main/java webapp-src = src/main/webapp resources = src/main/resources build = target/chapter02 These define the folders where your source code lies, where your libraries are located, and where to copy the compiled files and your resources. You do not have to declare them in a PROPERTIES file, but it makes re-using easier. Otherwise, you will have to write the folder names everywhere. This would make the build script hard to maintain if the folder layout changes. In the init target, we create the folders for the finished web application. The next is the assemble-webapp target, which depends on the init target. This means that if you execute the assemble-webapp target, the init target gets executed as well. This target will copy all the files belonging to your web application (such as the flow definition file and your JSP files) to the output folder. If you want to build your application, you will have to execute the compile target. It will initialize the output folder, copy everything your application needs to it, compile your Java source code, and copy the compiled files, along with the dependent libraries. If you want to use Apache Ivy for automatic dependency resolution, first, you have to download the distribution from http://ant.apache.org/ivy. This article refers to Version 2.0.0 Release Candidate 1 of Ivy. Unpack the ZIP file and put the ivy-2.0.0-rc1.jar file in your %ANT_HOME%lib folder. If you are using the Eclipse IDE, Ant is already built into the IDE. You can add the JAR file to its classpath by right-clicking on the task you want to execute and choosing Run As | Ant Build… In the appearing dialog, you can add the JAR file on the Classpath tab, either by clicking on Add JARs… and selecting a file from your workspace, or by selecting Add External JARs…, and looking for the file in your file system. Afterwards, you just have to tell Ant to load the required libraries automatically by modifying your build script. We have highlighted the important changes (to be made in the XML file) in the following source code: <project name="login.flow" default="compile"> ... <target name="resolve" description="--> retrieve dependencies with ivy"> <ivy:retrieve /> </target> ... </project> The last step, before we can actually build the project, involves specifying which libraries you want Ivy to download automatically. Therefore, we will now have to compose an ivy.xml file, stored in your project's root folder, which looks like this: <ivy-module version="2.0"> <info organisation="com.webflow2book" module="login.flow"/> <dependencies> <dependency org="org.springframework.webflow" name="org.springframework.binding" rev="2.0.5.RELEASE" /> <dependency org="org.springframework.webflow" name="org.springframework.js" rev="2.0.5.RELEASE" /> <dependency org="org.springframework.webflow" name="org.springframework.webflow" rev="2.0.5.RELEASE" /> </dependencies> ... </ivy-module> To keep the example simple, we only showed the Spring Web Flow entries of the file we just mentioned. In order to be able to build your whole project with Apache Ivy, you will have to add all other required libraries to the file. The org attribute corresponds to the groupId tag from Maven, as does the name attribute with the artifactId tag. The rev attribute matches the version tag in your pom.xml. Maven Maven is a popular application build system published by the Apache Software Foundation. You can get a binary distribution and plenty of information from the project's web site at http://maven.apache.org. After you have downloaded and unpacked the binary distribution, you have to set the M2_HOME environment variable to point to the folder where you unpacked the files. Additionally, we recommend adding the folder %M2_HOME%bin (on Microsoft® Windows system) or $M2_HOME/bin (on Unix or Linux systems) to your PATH variable. Maven has a configuration file called settings.xml, which lies in the M2_HOMEconf folder. Usually, you do not edit this file, unless you want to define proxy settings (for example, when you are in a corporate network where you have to specify a proxy server to access the Internet), or want to add additional package repositories. There are several plug-ins for the most popular IDEs around, which make working with Maven a lot easier than just using the command line. If you do not want to use a plug-in, you have to at least know that Maven requires your projects to have a specific folder layout. The default folder layout looks like this: The root folder, directly below your projects folder, is the src folder. In the main folder, you have all your source files (src/main/java), additional configuration files, and other resources you need (src/main/resources), and all JSP and other files you need for your web application (src/main/webapp). The test folder can have the same layout, but is used for all your test cases. Please see the project's website for more information on the folder layout. To actually build a project with Maven, you need a configuration file for your project. This file is always saved as pom.xml, and lies in the root folder of your project. The pom.xml for our example is too long to be included in this article. Nevertheless, we want to show you the basic layout. You can get the complete file from the code bundle uploaded on http://www.packtpub.com/files/code/5425_Code.zip. <project xsi_schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.webflow2book</groupId> <artifactId>chapter02</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>chapter02 Maven Webapp</name> <url>http://maven.apache.org</url> This is a standard file header where you can define the name and version of your project. Further, you can also specify how your project is supposed to be packaged. As we wanted to build a web application, we used the war option. Next, we can de?ne all the dependencies our project has to the external libraries: <dependencies> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>org.springframework.binding</artifactId> <version>2.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>org.springframework.js</artifactId> <version>2.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.webflow</groupId> <artifactId>org.springframework.webflow</artifactId> <version>2.0.5.RELEASE</version> </dependency> ... </dependencies> As you can see, defining a dependency is pretty straightforward. If you are using an IDE plug-in, the IDE can do most of this for you. To build the application, you can either use an IDE or open a command-line window and type commands that trigger the build. To build our example, we can enter the projects folder and type: mvn clean compile war:exploded This cleans up the target folder, compiles the source files, and compiles all necessary files for our web application in the target folder. If you use Tomcat, you can point your context docBase to the target folder. The application will be automatically deployed on the startup of Tomcat, and you can test your application.
Read more
  • 0
  • 0
  • 3351

article-image-show-additional-information-users-and-visitors-your-plone-site
Packt
12 Oct 2009
5 min read
Save for later

Show Additional Information to Users and Visitors of Your Plone Site

Packt
12 Oct 2009
5 min read
(For more resources on Plone, see here.) What's a portlet, anyway? A portlet is a chunk of information that can be shown outside of the main content area of a page. In the following screenshot of Plone's default home page, the Log in box and the calendar are portlets. Plone's default theme has two portlet managers that control the assignment of portlets on the right and left sidebars of the page. You can place portlets into these slots on the page. It's also possible to add portlet manager slots to a custom theme so that you can display portlets in other areas of the page, but that's beyond the scope of this book. For more information, refer to: http://plone.org/documentation/how-to/adding-portlet-managers. There are two things that we need to know about portlets before we dive into adding them: Portlets can only be added to portlet managers. They can't be added into the body content of your pages. Portlets can be assigned to folders, content types, or user groups, and will cascade down through the site hierarchy unless you explicitly block inheritance. Plone's built-in portlets Plone ships with a generous assortment of basic portlets. Here's a quick list of Plone's default portlet offerings: Login: Shows Plone's login box to anonymous users; is hidden if a user is already logged in Collection portlet: Shows the results of a Collection Review list: Visible only to the users with the Reviewer role; this portlet shows a list of items that users have submitted for review before publishing RSS feed: Shows a list of items in an RSS feed Classic portlet: A wrapper for Zope 2 style portlets, which may have been developed prior to the advent of Plone 3 and its new portlet system Calendar portlet: Shows a simple calendar that highlights the dates of upcoming events for your site Search: Shows Plone's search box useful if you have chosen to disable the standard search box, and want to show it in a sidebar instead Recent items: Shows the most recently-published content items on your site Static text portlet: Shows a chunk of static, editable HTML content; this is one of Plone's most versatile and useful portlets Navigation: Shows the navigation tree Events: Shows upcoming published events on your site You're likely only to use Classic portlets if you are using an add-on product that hasn't fully embraced the new style of building portlets, or if you are building your own custom portlets. Add-on portlets Many add-on products for Plone will supply one or more relevant portlets when the product is installed. There are also additional standalone portlets available as separate add-on products. Among the most useful standalone add-on portlets are: TAL Portlet: A portlet that allows you to write your own simple portlets in Plone's templating language, TAL. Optionally, you could just write a Classic portlet. Feedmixer: A portlet that allows you to aggregate multiple RSS feeds into a single portlet. These products can be found in the Products section of Plone.org. Adding portlets There are three ways to add portlets to your site: Add portlets to specific locations on your site. Add portlets that are associated with specific content types—for example, a portlet that shows on all News Items. Add portlets that are shown only to specific groups of users in your site. Adding portlets to specific sections of your site We'll start with adding portlets to a specific section of your site, as this is the most common and the simplest thing to do. Log in to your site (via the Log in portlet) and look at the bottom of the rightmost sidebar for the Manage portlets link. This will take you to the Manage portlets screen. Managing Portlets PeacefullyBecause you were on the front page of your site, when you clicked on the Manage portlets link, you are now managing the portlets for your entire site. If you only want to manage portlets for a single section of your site, first navigate to that section, and then click on the Manage portlets link. The header of the Manage Portlets screen will tell you which section of the site you are in. The Manage Portlets screen tells you that certain portlets are already assigned to all of the pages of your site. In the example above, the left sidebar portlet manager has the Navigation portlet and the Log in portlet. The right sidebar portlet manager has the Review List, News, Events and Calendar portlets. Moving and Removing PortletsYou can move existing portlets around within a portlet manager by clicking on the up and down arrows within the portlet. You can remove a portlet from the portlet manager by clicking on the red X. To add a portlet to your site, select the Add portlet... drop-down menu at the top of either the right or left sidebar, and choose a portlet type to be added. For practice, let's try adding a static content portlet to the right sidebar. This screen contains the familiar Kupu-powered rich text editing widget, along with: A Portlet header (title) field. A Portlet footer field. A optional hyperlink field, which will be clickable from the portlet header and footer. An Omit portlet border checkbox. If selected, this hides the portlet header, footer, and border. This is very useful if you only want to place an image or some fl oating text in your sidebar. Enter some text into your new portlet, click on the Save button at the bottom of the screen, and then click on the Home tab to return to your site's homepage. You should now see your new static text portlet. If you click around the site, you'll continue to see the portlet on all of the pages of your site.
Read more
  • 0
  • 0
  • 6331

article-image-blog-cms
Packt
12 Oct 2009
10 min read
Save for later

Blog CMS

Packt
12 Oct 2009
10 min read
Let's get started right away. The first question-do I need a self-hosted or service-based CMS? Blogs have taken the Internet by storm. They started like simple diaries and have grown to be full-fledged CMSs now. If you want to start a blog, you have the following two options: Sign up with a hosted blog service such as WordPress.com, Typepad.com, Blogger.com, or any other similar services available Set up blogging software, such as WordPress, Movable Type, ExpressionEngine, and so on, on your own server If you are a casual blogger, signing up with a hosted service is a suitable choice. But if you want full control of your blog, setting up your own system is the best option. It's not very difficult—you could do it within five minutes. We will cover only self-hosted solutions for this article. But you can easily apply this knowledge to a blog service. Top blogging CMSs  WordPress (www.WordPress.org) is the most popular self-hosted blogging software. Hundreds of thousands of sites run on WordPress, and tens of millions of people see WordPress-driven content every day. The following images are of the PlayStation ( http://blog.us.playstation.com/ ) and the People ( http://offtherack.people.com/ ) blog sites, which use WordPress: Movable Type (www.movabletype.org) is another longtime favorite. It's very easy to use and has a strong fan following. There are many contenders after the top two blogging CMSs. All general-purpose CMSs have a blogging component. Many old blog software applications are no longer actively maintained. There are new entrants on the scene that focus on niches, such as photo blogging. Let us cover the top choices We can't cover all of the blog software in this article. So, we will only cover WordPress at length. We will talk about Movable Type and ExpressionEngine briefly. At the end, we will touch upon other blogging software. What we are interested in is to find out answers to the following questions: What sort of a site is that CMS good for? How easy is it to build a site? How easy is it to edit content? What's its plug-in/template support like? How extensible/customizable is it? What are the interesting or high-profile examples of that CMS? Taking WordPress for a test drive Let's try creating a site structure, adding and editing content, applying design templates, and making a few customizations with WordPress to see how it performs. Time for action-managing content with WordPress Log in to the administration panel of your WordPress installation. Click on the New Post link in the top bar. This opens the Add New Post page.Enter a title for your first blog post where your cursor is blinking. We will enter definition of the word Yoga for our Yoga Site. Start writing your text in the large text entry box. It's a WYSIWYG editor. You can use buttons in the toolbar to format text, insert links, and so on. Let's insert an image into our post. Click on the first icon next to Upload/Insert. When you move your mouse over it, you will see Add an Image in the tooltip. Click on that icon. Upload a file from your computer. Once a file is uploaded, you can enter additional parameters for this image. This includes Title, Caption, Alignment, a link to open when an image is clicked, and so on. Here's how your screen may look at this stage. Click on Insert into Post to add this image to your post. Complete writing the blog entry. If you want to add tags (keywords) to this post, you can do that from the Tagssection at right. WordPress will autocomplete long tags and will create newones as you Add them. We have not yet created any categories for our blog. Navigate to the Categories section below Tags. Click on the + Add New Category link. Enter Background as your category name and Add it. Any new categories youadd are selected automatically. Notice that you can post a blog entry in multiplecategories at once. There are a few other options too. There are the settings for Discussion. We want to allow both comments and trackbacks, so keep both options checked. Scroll up and click on the Publish button on the right to make this post live. Click on View Post at the top left to see how your site looks at the moment. What just happened? We published a new blog post with WordPress! This was the first time we used WordPress, but we could accomplish everything we needed to post this entry just from one screen. This is an important thing. Many CMSs require that you set up categories and images separately. This means you have to know the system before you can use it! WordPress allows you to learn about the system while using it. All sections in the Add New Postpage are well-labeled. There are sufficient descriptions, and what is not needed is hidden by default. Our title automatically became a search engine friendly permalink for this post. We could format our text with a simple WYSIWYG editor. It was packed with features—spell check, full screen editing, and further formatting options via Kitchen Sink. The editor allowed advanced editing by switching to the HTML mode. Adding an image was very easy. Upload, set options, and insert. We could select a previously uploaded image from the gallery, too. We could enter keyword tags for a post quickly. Selecting a category and adding new categories was simple. We created a new category on the Add New Post page itself. WordPress is intelligent enough to understand that if we added a new category on a post page, we would want to use it for that post. So, it was selected automatically. Advance options were available, but were hidden by default. We could publish the post right away, or at a later date. WordPress could also keep history of all the revisions we make to a post, could preview the post, and would auto-save it frequently. WordPress looks easy and powerful so far. Let us look at how we can harness it further. Surviving blog jargon and benefitting from itBlogs have their own terminology. You may not have heard of trackbacks, pingbacks, tags, or permalinks. You can learn more about these terms from http://en.wikipedia.org/wiki/List_of_blogging_terms and http://www.dailyblogtips.com/the-bloggers-glossary/. Similarly, there are excellent features that blogs have—comments, aggregating content from other sources, ability to get updates via RSS feeds, and so on. I recommend you to go through these glossaries to learn more about blogs. Extending WordPress Managing content with WordPress seems easy. We want to see how easy is it to customize its design and extend its features. Let's begin with the action. Time for action-customizing the design Find some themes you like. You can browse through theme galleries at http://WordPress.org/extend/themes/ or Google WordPress themes. There are thousands of free and paid themes available for WordPress. Download some themes that you like. Unzip each theme's ZIP file. Each theme should create a new folder for itself. Upload all these folders to the wp-content/themes folder on your server. In WordPress, go to Admin  Appearance|. You should see new themes you uploaded in the Available Themes section. The page also lists the WordPress Classic andDefault themes. We have three new themes showing up. Click on one of the themes to see a live preview. This is how it will look. Review all themes. Activate the one you like the most by clicking on the Activate link at the top right in the preview window. We liked oriental and activated it. Our site now shows up just like the live preview. What just happened? We installed a new design theme for our WordPress blog. We downloaded three themes from the Web, unzipped them, and uploaded them to our WordPress themes folder. The themes showed up in WordPress admin. Clicking on a theme showed a live preview. This made our decision easy. We activated the theme we liked. That's how easy it was to change the design of our blog! If you recall, installing a new design was similar in Joomla!, except that Joomla! allowed us to upload a ZIP file using its administration interface itself. The tricky part in giving a new design to your site was shortlisting and selecting a design, not setting it up. Customizing the theme Consider the following theme editor in WordPress If you want to further customize your theme, you can do that. In fact, you have full control over how your site looks with WordPress. You can use Appearance | Editor to change individual theme files. We recommend making template customizations on a local installation of WordPress first.Once you get everything done according to your choice, you can upload the changed files to the theme's folder and activate it. WordPress widgets Widgets are content blocks that can be used in a theme. Search, RSS feeds, Blog Post Archives, Tag Cloud, and Recent Posts are some of the built-in widgets available in WordPress. You can turn them on or off independently, determine their position in the sidebar, and also change their settings. Go to the Appearance | Widgets page to take over the control of WordPress widgets. Add unlimited power with plug-ins Our Yoga Site needs a lot more than just the core content management. How can we achieve that with WordPress? And will it be wise to use WordPress for our Yoga Site? The WordPress plug-in architecture is solid. You will find hundreds of high-quality plug-ins from photo galleries to e-commerce. But remember that the core of WordPress is a blog engine, which chronologically displays content under set categories. It encourages sharing and contribution. Theoretically, you can customize WordPress to any need you have. But we recommend you to evaluate the most important features for your site and then decide whether you want to use WordPress as a base, or something else. I use WordPress for my blog and have a range of plug-ins installed. WordPress is painless, and it allows me to focus on the core goal of my blog—sharing knowledge. Take a look at the list of plug-ins on my blog at www.mehtanirav.com. You may have noticed a few plug-ins to handle comments and spam. Why would you need that? Well, because you will end up spending all your time removing spam comments from your system if you don't have them activated. Comment spam is a real pain with all blogs. Spammers have written spam-bots (automatic software) that keep posting junk comments on your blog. If you don't protect comment submission, your blog will soon be flooded with advertisements of pills you don't want to take and a lot of other things you don't want your visitors to attend to. Comment protection plug-ins are the first you should install. I use Akismet with Simple Math. Simple Math poses a simple mathematical question to the comment writer. A human can easily answer that. This takes care of most of the spam comments. Comments that pass through this test need to pass through Akismet. Askimet is an excellent spam-protection plug-in from the WordPress team. These two plug-ins kill almost 99.99% of spam comments on my blog. Once I am left with legitimate comments, I can go to WordPress's Admin | Comments, and Approve, Unapprove, Delete, or Mark as Spam all comments. The Edit Comments screen looks like the following screenshot:| WordPress is a superb choice for creating a blog. It can be used as a general-purpose CMS as well. We have covered most of the day-to-day operations with WordPress so far. Here are some additional resources for you.
Read more
  • 0
  • 1
  • 6214
article-image-creating-our-first-module-using-drupal-6-part2
Packt
12 Oct 2009
11 min read
Save for later

Creating Our First Module using Drupal 6 (Part2)

Packt
12 Oct 2009
11 min read
Using Goodreads Data So far, we have created a basic module that uses hook_block() to add block content and installed this basic module. As it stands, however, this module does no more than simply displaying a few lines of static text. In this article, we are going to extend the module's functionality. We will add a few new functions that retrieve and format data from Goodreads. Goodreads makes data available in an XML format based on RSS 2.0. The XML content is retrieved over HTTP (HyperText Transport Protocol), the protocol that web browsers use to retrieve web pages. To enable this module to get Goodreads content, we will have to write some code to retrieve data over HTTP and then parse the retrieved XML. Our first change will be to make a few modifications to goodreads_block(). Modifying the Block Hook We could cram all of our new code into the existing goodreads_block() hook; however, this would make the function cumbersome to read and difficult to maintain. Rather than adding significant code here, we will just call another function that will perform another part of the work. /** * Implementation of hook_block */function goodreads_block($op='list' , $delta=0, $edit=array()) { switch ($op) { case 'list': $blocks[0]['info'] = t('Goodreads Bookshelf'); return $blocks; case 'view': $url = 'http://www.goodreads.com/review/list_rss/' .'398385' .'?shelf=' .'history-of-philosophy'; $blocks['subject'] = t('On the Bookshelf'); $blocks['content'] = _goodreads_fetch_bookshelf($url); return $blocks; }} The preceding code should look familiar. This is our hook implementation as seen in the previous article. However, we have made a few modifications, indicated by the highlighted lines. First, we have added a variable, $url, whose value is the URL of the Goodreads XML feed we will be using (http://www.goodreads.com/review/list_rss/398385?shelf=history-of-philosophy). In a completely finished module, we would want this to be a configurable parameter, but for now we will leave it hard-coded. The second change has to do with where the module is getting its content. Previously, the function was setting the content to t('Temporary content'). Now it is calling another function: _goodreads_fetch_bookshelf($url). The leading underscore here indicates that this function is a private function of our module—it is a function not intended to be called by any piece of code outside of the module. Demarcating a function as private by using the initial underscore is another Drupal convention that you should employ in your own code. Let's take a look at the _goodreads_fetch_bookshelf() function. Retrieving XML Content over HTTP The job of the _goodreads_fetch_bookshelf() function is to retrieve the XML content using an HTTP connection to the Goodreads site. Once it has done that, it will hand over the job of formatting to another function. Here's a first look at the function in its entirety: /** * Retrieve information from the Goodreads bookshelp XML API. * * This makes an HTTP connection to the given URL, and * retrieves XML data, which it then attempts to format * for display. * * @param $url * URL to the goodreads bookshelf. * @param $num_items * Number of items to include in results. * @return * String containing the bookshelf. */function _goodreads_fetch_bookshelf($url, $num_items=3) { $http_result = drupal_http_request($url); if ($http_result->code == 200) { $doc = simplexml_load_string($http_result->data); if ($doc === false) { $msg = "Error parsing bookshelf XML for %url: %msg."; $vars = array('%url'=>$url, '%msg'=>$e->getMessage()); watchdog('goodreads', $msg, $vars, WATCHDOG_WARNING); return t("Getting the bookshelf resulted in an error."); } return _goodreads_block_content($doc, $num_items); // Otherwise we don't have any data}else { $msg = 'No content from %url.'; $vars = array('%url' => $url); watchdog('goodreads', $msg, $vars, WATCHDOG_WARNING); return t("The bookshelf is not accessible."); }} Let's take a closer look. Following the Drupal coding conventions, the first thing in the above code is an API description: /** * Retrieve information from the Goodreads bookshelp XML API. * * This makes an HTTP connection to the given URL, and retrieves * XML data, which it then attempts to format for display. * * @param $url * URL to the goodreads bookshelf. * @param $num_items * Number of items to include in results. * @return * String containing the bookshelf. */ This represents the typical function documentation block. It begins with a one-sentence overview of the function. This first sentence is usually followed by a few more sentences clarifying what the function does. Near the end of the docblock, special keywords (preceded by the @ sign) are used to document the parameters and possible return values for this function. @param: The @param keyword is used to document a parameter and it follows the following format: @param <variable name> <description>. The description should indicate what data type is expected in this parameter. @return: This keyword documents what type of return value one can expect from this function. It follows the format: @return <description>. This sort of documentation should be used for any module function that is not an implementation of a hook. Now we will look at the method itself, starting with the first few lines. function _goodreads_fetch_bookshelf($url, $num_items=3) { $http_result = drupal_http_request($url); This function expects as many as two parameters. The required $url parameter should contain the URL of the remote site, and the optional $num_items parameter should indicate the maximum number of items to be returned from the feed. While we don't make use of the $num_items parameter when we call _goodreads_fetch_bookshelf() this would also be a good thing to add to the module's configurable parameters. The first thing the function does is use the Drupal built-in drupal_http_request() function found in the includes/common.php library. This function makes an HTTP connection to a remote site using the supplied URL and then performs an HTTP GET request. The drupal_http_request() function returns an object that contains the response code (from the server or the socket library), the HTTP headers, and the data returned by the remote server. Drupal is occasionally criticized for not using the object-oriented features of PHP. In fact, it does—but less overtly than many other projects. Constructors are rarely used, but objects are employed throughout the framework. Here, for example, an object is returned by a core Drupal function. When the drupal_http_request() function has executed, the $http_result object will contain the returned information. The first thing we need to find out is whether the HTTP request was successful—whether it connected and retrieved the data we expect it to get. We can get this information from the response code, which will be set to a negative number if there was a networking error, and set to one of the HTTP response codes if the connection was successful. We know that if the server responds with the 200 (OK) code, it means that we have received some data. In a more robust application, we might also check for redirect messages (301, 302, 303, and 307) and other similar conditions. With a little more code, we could configure the module to follow redirects. Our simple module will simply treat any other response code as indicating an error: if ($http_result->code == 200) { // ...Process response code goes here... // Otherwise we don't have any data} else { $msg = 'No content from %url.'; $vars = array( '%url' => $url ); watchdog('goodreads', $msg, $vars, WATCHDOG_WARNING); return t("The bookshelf is not accessible.");} First let's look at what happens if the response code is something other than 200: } else { $msg = 'No content from %url.'; $vars = array( '%url' => $url ); watchdog('goodreads', $msg, $vars, WATCHDOG_WARNING); return t("The bookshelf is not accessible.");} We want to do two things when a request fails: we want to log an error, and then notify the user (in a friendly way) that we could not get the content. Let's take a glance at Drupal's logging mechanism. The watchdog() Function Another important core Drupal function is the watchdog() function. It provides a logging mechanism for Drupal. Customize your loggingDrupal provides a hook (hook_watchdog()) that can be implemented to customize what logging actions are taken when a message is logged using watchdog(). By default, Drupal logs to a designated database table. You can view this log in the administration section by going to Administer | Logs. The watchdog() function gathers all the necessary logging information and fires off the appropriate logging event. The first parameter of the watchdog() function is the logging category. Typically, modules should use the module name (goodreads in this case) as the logging category. In this way, finding module-specific errors will be easier. The second and third watchdog parameters are the text of the message ($msg above) and an associative array of data ($vars) that should be substituted into the $msg. These substitutions are done following the same translation rules used by the t() function. Just like with the t() function's substitution array, placeholders should begin with !, @, or %, depending on the level of escaping you need. So in the preceding example, the contents of the $url variable will be substituted into $msg in place of the %url marker. Finally, the last parameter in the watchdog() function is a constant that indicates the log message's priority, that is, how important it is. There are eight different constants that can be passed to this function: WATCHDOG_EMERG: The system is now in an unusable state. WATCHDOG_ALERT: Something must be done immediately. WATCHDOG_CRITICAL: The application is in a critical state. WATCHDOG_ERROR: An error occurred. WATCHDOG_WARNING: Something unexpected (and negative) happened, but didn't cause any serious problems. WATCHDOG_NOTICE: Something significant (but not bad) happened. WATCHDOG_INFO: Information can be logged. WATCHDOG_DEBUG: Debugging information can be logged. Depending on the logging configuration, not all these messages will show up in the log. The WATCHDOG_ERROR and WATCHDOG_WARNING levels are usually the most useful for module developers to record errors. Most modules do not contain code significant enough to cause general problems with Drupal, and the upper three log levels (alert, critical, and emergency) should probably not be used unless Drupal itself is in a bad state. There is an optional fifth parameter to watchdog(), usually called $link, which allows you to pass in an associated URL. Logging back ends may use that to generate links embedded within logging messages. The last thing we want to do in the case of an error is return an error message that can be displayed on the site. This is simply done by returning a (possibly translated) string: return t("The bookshelf is not accessible."); We've handled the case where retrieving the data failed. Now let's turn our attention to the case where the HTTP request was successful. Processing the HTTP Results When the result code of our request is 200, we know the web transaction was successful. The content may or may not be what we expect, but we have good reason to believe that no error occurred while retrieving the XML document. So, in this case, we continue processing the information: if ($http_result->code == 200) { // ... Processing response here... $doc = simplexml_load_string($http_result->data); if ($doc === false) { $msg = "Error parsing bookshelf XML for %url: %msg."; $vars = array('%url'=>$url, '%msg'=>$e->getMessage()); watchdog('goodreads', $msg, $vars, WATCHDOG_WARNING); return t("Getting the bookshelf resulted in an error."); } return _goodreads_block_content($doc, $num_items); // Otherwise we don't have any data} else { // ... Error handling that we just looked at. In the above example, we use the PHP 5 SimpleXML library. SimpleXML provides a set of convenient and easy-to-use tools for handling XML content. This library is not present in the now-deprecated PHP 4 language version. For compatibility with outdated versions of PHP, Drupal code often uses the Expat parser, a venerable old event-based XML parser supported since PHP 4 was introduced. Drupal even includes a wrapper function for creating an Expat parser instance. However, writing the event handlers is time consuming and repetitive. SimpleXML gives us an easier interface and requires much less coding. For an example of using the Expat event-based method for handling XML documents, see the built-in Aggregator module. For detailed documentation on using Expat, see the official PHP documentation: http://php.net/manual/en/ref.xml.php. We will parse the XML using simplexml_load_string(). If parsing is successful, the function returns a SimpleXML object. However, if parsing fails, it will return false. In our code, we check for a false. If one is found, we log an error and return a friendly error message. But if the Goodreads XML document was parsed properly, this function will call another function in our module, _goodreads_block_content(). This function will build some content from the XML data.
Read more
  • 0
  • 0
  • 1554

article-image-drupal-6-content-construction-kit-cck
Packt
09 Oct 2009
6 min read
Save for later

Drupal 6 Content Construction Kit (CCK)

Packt
09 Oct 2009
6 min read
Views module provide administrators with the means to modify how Drupal displays lists of content, and CCK exposes its fields to the Views module, making them perfect partners when it comes to creating custom content and then displaying that content in a highly configurable manner. At the time of writing, Views is not available for Drupal 6 (although the module is being actively developed and should hopefully be ready by the time you read this) so it is left as an exercise to download and install it, and create at least one new View, utilizing fields created in the following sections. Installing CCK CCK is available, so go ahead and download the latest version and extract the file to your modules folder. CCK adds its own section to the Modules page under Site building: There are a number of interdependent sections for this module, but all of them rely on the first option, Content, so go ahead and enable this first. We are going to look over all the features provided by CCK, by default, in this section. So go ahead and enable those modules that rely only on Content. With that done, enable the remaining options so that you end up with everything working, like this: Notice that some of the options are disabled to prevent us from inadvertently disabling an option that is required by something else. If, for example, you wish to disable Text, then disable Node Reference and User Reference first. Working with CCK With all the options enabled, we can now go ahead and create a new content type. Actually, it is possible to create new content types without the use of CCK, it's just that the new content types will look pretty much like the standard content types already available, because there are no really interesting fields to add. Head over to Content types under Content management and select the Add content type field to bring up the following page: The identification section is pretty straightforward. You can go ahead and fill in whatever new content settings are appropriate. Of special interest is the Submission form settings below this that allows you to decide whether the default Title and Body fields should be changed or even retained (in the case of the Body field): In the case of the Endangered Species content type, it doesn't really make sense to have a species Title, rather a Common name makes more sense. Leaving the Body field label blank will cause this field to be omitted completely in the event that it is not suitable for the type of content you have in mind. You may have noticed that there are several additional tabs to the right of Add content type tab that provide additional functionality. These options are discussed a little later on in this section. So for now, go ahead and fill out the Name, Type, and Description fields and click Save content type to add this to the default list: We are now ready to begin customizing this new type utilizing whatever options are available—depending on what is or is not enabled. It is possible to customize any type that is available on Drupal, including the default ones like Blog entry or Poll, but to begin with it is best to leave these alone. To begin working on the new content type, click on edit in the Endangered Species row. We can now look at the various aspects of working with content types, beginning with… Adding Fields Select the Add field tab to bring up the following page: This dialog allows you to specify the new field's machine readable name and then select what type of input it is going to be. Presently, only the Create new field section is displayed on this page, because we have yet to add new fields. Once there is at least one custom field available, this page will have an additional section allowing existing fields to be added directly from any content type (you can come back here once there are a few saved fields): Regardless, the Create new field list presently comprises of the following options: Node Reference – Allows the poster to reference another node using its ID value Integer, Decimal, Float – Allows posters to store numbers in various formats Text – Allows posters to enter content User Reference – Allows posters to reference other users. Remember that this list is subject to change, depending on whether you disable various components of the default package, for example, Node Reference or User Reference, or include additional modules that add field types such as Date or Fivestar. Each value type comes with a set of options for how that data should be entered. Looking at the Integer type, we can see that users can be prompted for an integer with a Text Field, Select list, Check boxes, and radio buttons—in this case, the Select list is going to be used. Be careful about how information is stored—it is important to be efficient. For example, don't store information as text when there is only a certain number of options available, instead, store them as a number and provide the right input type to display the various options appropriately. To demonstrate this point, consider that at the moment, the numbers_in_wild field is set as an integer with the Select list input type. We are not going to provide a select list of every possible integer, but we are going to represent a range of numbers with an integer. For example, the value 1 will correspond to the range 1-10, 2 will correspond to 11-100, and so on. With the new field created, the configuration page for this field (Click on configure in the Operations column of the Manage fields page) now displays the current settings available. To begin with, the options in the Endangered Species settings are not of much interest as we have not specified what data this field will hold. To do this, scroll down the page to the Global settings section. From here, you can decide on how the data will be presented to the user and whether or not the field itself will be compulsory or not: Along with the Allowed values list used to input key-value pairs, there are a few other settings that may be of use, depending on what data the field should capture. Minimum and Maximum values along with Suffix and Prefix values allow for some minor input validation, as well as some useful display properties like currency denominations or physical units of measurement.
Read more
  • 0
  • 0
  • 3081
Modal Close icon
Modal Close icon