Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
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-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-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-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-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-inviting-friends-email-social-web-application-django-10
Packt
12 Oct 2009
6 min read
Save for later

Inviting Friends via Email on Social Web Application with Django 1.0

Packt
12 Oct 2009
6 min read
Django is an open source web framework that enables you to build clean and feature-rich web applications with minimal time and effort. Django is written in Python, a general purpose language that is well-suited for developing web applications. Social bookmarking is one such application. Inviting friends via email Enabling our users to invite their friends carries many benefits. People are more likely to join our site if their friends are already using it. After they join, they will also invite their friends, and so on, which means an increasing number of users for our application. Therefore, it is a good idea to offer an "Invite a friend" feature. This is actually a common functionality found in many Web 2.0 applications. Building this feature requires the following components: An Invitation data model to store invitations in the database A form in which users can type the emails of their friends and send invitations An invitation email with an activation link A mechanism for processing activation links sent in email Throughout this article, we will implement each component. But because this article involves sending emails, we first need to configure Django to send emails by adding some options to the settings.py file. So, open the settings.py file and add the following lines to it: SITE_HOST = '127.0.0.1:8000'DEFAULT_FROM_EMAIL = 'Django Bookmarks <django.bookmarks@example.com>'EMAIL_HOST = 'mail.yourisp.com'EMAIL_PORT = ''EMAIL_HOST_USER = 'username'EMAIL_HOST_PASSWORD = 'password' Let's see what each variable does. SITE_HOST: This is the host name of your server. Leave it as 127.0.0.1:8000 for now. We will change this, when we deploy our server. DEFAULT_FROM_EMAIL: This is the email address that appears in the From field of emails sent by Django. EMAIL_HOST: This is the host name of your email server. If you are using a development machine that doesn't run a mail server (which is most likely the case), then you need to put your ISP's outgoing email server here. Contact your ISP for more information. EMAIL_PORT: This refers to the port number of the outgoing email server. If you leave it empty, the default value (25) will be used. You also need to obtain this from your ISP. EMAIL_HOST_USER and EMAIL_HOST_PASSWORD : This refers to the username and password for the outgoing email server. For the host username, input your username and your email server (as shown in the previous code). Leave the fields empty if your ISP does not require them. To verify that your settings are correct, launch the interactive shell and enterthe following: >>> from django.core.mail import send_mail>>> send_mail('Subject', 'Body of the message.', 'from@example.com', ['your_email@example.com']) Replace your_email@example.com with your actual email address. If the above call to send_mail does not raise an exception and you receive the email, then all is set. Otherwise, you need to verify your settings with your ISP and try again. Once the settings are correct, sending an email in Django is a piece of cake! We will use send_mail to send the invitation email. But first, let's create a data model for storing invitations. The invitation data model An invitation consists of the following information: Recipient name Recipient email The User object of the sender We also need to store an activation code for the invitation. This code will be sent in the invitation email. The code will serve two purposes: Before accepting the invitation, we can use the code to verify that the invitation actually exists in the database After accepting the invitation, we can use the code to retrieve the invitation information from the database and create friendship relationships between the sender and the recipient With this in mind, let's create the Invitation data model. Open the bookmarks/models.py file and append the following code to it: class Invitation(models.Model): name = models.CharField(max_length=50) email = models.EmailField() code = models.CharField(max_length=20) sender = models.ForeignKey(User) def __unicode__(self): return u'%s, %s' % (self.sender.username, self.email) There shouldn't be anything new or difficult to understand in this model. We simply defined fields for the recipient name, recipient email, activation code, and the sender of the invitation. We also created a __unicode__ method for debugging, and enabled the model in the administration interface. Do not forget to run manage.py syncdb to create the new model's table in the database. Next, we will add a method for sending the invitation email. The method will use classes and methods from several packages. So, put the following import statements at the beginning of the bookmarks/models.py file, and append the send method to the Invitation data model in the same file: from django.core.mail import send_mailfrom django.template.loader import get_templatefrom django.template import Contextfrom django.conf import settingsclass Invitation(models.Model): [...] def send(self): subject = u'Invitation to join Django Bookmarks' link = 'http://%s/friend/accept/%s/' % ( settings.SITE_HOST, self.code ) template = get_template('invitation_email.txt') context = Context({ 'name': self.name, 'link': link, 'sender': self.sender.username, }) message = template.render(context) send_mail( subject, message, settings.DEFAULT_FROM_EMAIL, [self.email] ) The method works by loading a template called invitation_email.txt and passing the following variables to it: the name of the recipient, the activation link, and the sender username. The template is then used to render the body of the invitation email. After that, we used send_mail to send the email. There are several observations to make here: The format of the activation link is http://SITE_HOST/friend/accept/CODE/. We will write a view to handle such URLs later in this article. This is the first time we use a template to render something other than a web page. As you can see, the template system is quite flexible and allows us to build emails as well as web pages, or any other text. We used the get_template and render methods to build the message body as opposed to the usual render_to_response call. If you remember, this is how we rendered templates early in the book. We are doing this here because we are not rendering a web page. The last parameter of send_mail is a list of recipient emails. Here we are passing only one email address. But if you want to send the same email to multiple users, you can pass all of the email addresses in one list to send_mail. Since the send method loads a template called invitation_email.txt, create a file with this name in the templates folder and insert the following content into it: Hi {{ name }},{{ sender }} invited you to join Django Bookmarks, a website where you can post and share your bookmarks with friends!To accept the invitation, please click the link below:{{ link }}-- Django Bookmarks Team Once we write the send method, our Invitation data model is ready. Next, we will create a form that allows users to send invitations.
Read more
  • 0
  • 0
  • 5484

article-image-social-bookmarking-blogger-part-2
Packt
12 Oct 2009
6 min read
Save for later

Social Bookmarking in Blogger: Part 2

Packt
12 Oct 2009
6 min read
Adding buttons gives the site a more homemade feel, but it is time consuming to hunt down the links to the different services on the social networking sites. Wouldn't it be great if there was a third-party service out there that did the gathering for you? AddThis (http://www.addthis.com) offers a multi-bookmark widget popular with many bloggers. Offering Multiple Bookmarks with One Button Using a widget like the one offered by AddThis frees you to spend your time blogging. You can choose to show all the main bookmark networks or pick and choose from an extensive list. We'll configure the widget and then install it on our blog. Time for Action!—Offering Multiple Bookmarks with AddThis Register at the AddThis (http://www.addthis.com) site. Georgia has already created an account for Fruit for All. The AddThis Social Widget Builder screen has multiple options to customize the widget code. Choose the Bookmarking widget option from the Which kind of widget? drop-down box. Select the style of bookmark button you want to use. We will choose the second one. The on a Blog option should be selected for Where? Choose Blogger for the Blogging Platform and then click Get Your Free Button>> for the code. Next, AddThis will provide you with the code. Copy the code from the site or type the code below in place of the button links, above the <p class='post-footer-line post-footer-line-2'> tag in the template code: <!-- AddThis Bookmark Post Dropdown BEGIN --> <div> <script type='text/javascript'>addthis_url='<data:post.url/>'; addthis_title='<data:post.title/>'; addthis_pub='fruitforall';</script> <script src='http://s7.addthis.com/js/addthis_widget.php?v=12' type='text/javascript'></script> </div> <!-- AddThis Bookmark Post Dropdown END --> Save the template changes and view the blog. Try hovering the cursor over the Bookmark button to see whether the list of bookmarks appears. The button looks great. We need to test an icon to see how AddThis submits posts. Click the Del.icio.us icon to bring up the submission window. The URL, description (title), and tags were auto populated for us. Taking a note of the recommended tags will help us label future posts, and will guide us in adding more labels to the current post. What Just Happened? The AddThis button replaced our group of social bookmark buttons. When the visitor hovers their cursor over the button, a list of social bookmark icons appear. The visitor also has the option to choose from social bookmarks not listed in the main group. A new window opens with a submission form for the service we selected. After the form is filled out, AddThis collects statistical data for us and displays it graphically on our AddThis account page. The icons displayed on the button can be changed on the AddThis site. You can't predict which bookmarks your visitors use. Using a multiple bookmark aggregator such as AddThis keeps your posts free of bookmark clutter while giving visitors more bookmarking choices. There are other options as well. ShareThis (http://www.sharethis.com) has recently released the latest version of its multiple bookmark service, which includes tracking. It is available at http://sharethis.com/publisher/. Adding Dynamic Counters to Bookmark Links Showing counters on social bookmark icons is becoming popular. Dynamic counters are offered by bookmark services Reddit, Del.icio.us, Ma.gnolia, and Digg. Bookmark services are adding their own counters every day. Readers can quickly see if a post has already been submitted to a service and can vote to increase or decrease the popularity of the post while still at the blog. We will add the popular del.icio.us dynamic bookmark and examine the features it offers. We will then explore and then explore using Feedburner Flare (http://www.feedburner.com) to show multiple counters easily. Time for Action!—Adding Dynamic Links with Counters to Posts Navigate to the Edit HTML screen on the blog, and click the Expand Widget Templates checkbox. Type the following block of code directly above the <p class='post-footer-line post-footer-line-2'> tag in the template code, deleting any existing social bookmark code we added before: <script type="text/javascript">if (typeof window.Delicious == "undefined") window.Delicious = {}; Delicious.BLOGBADGE_DEFAULT_CLASS = 'delicious- blogbadge-line';</script> <script src="http://images.del.icio.us/static/js/ blogbadge.js"></script> Save the template, and view the blog to see the changes. An example of how it should look now is shown in the following screenshot: Are there any differences between the information captured using this bookmark and others? Let's test the bookmark and find it out. Click on bookmark this on the del.icio.us button and review the results: The bookmark does not display the actual post title and post URL. We will need to customize it to display that information when the reader submits the post. What Just Happened? We inserted a ready made counter bookmark script from the del.icio.us site into our template code. The first JavaScript code snippet will check to see if a link to del.icio.us already exists. If it does not, a special default CSS class is set to control the appearance of the badge. The code is shown for reference below: <script type="text/javascript">if (typeof window.Delicious == "undefined") window.Delicious = {}; Delicious.BLOGBADGE_DEFAULT_CLASS = 'delicious-blogbadge-line';</script> Calling the code controlling the badge counter is done with the final script tag. It links to an external JavaScript file stored at the del.icio.us site. <script src="http://images.del.icio.us/static/js/blogbadge.js"> </script> The script counts how many times readers have recommended the blog site to del.icio.us using their own script counter. The number shown will increase each time the site is bookmarked by someone on del.icio.us.
Read more
  • 0
  • 0
  • 2397
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-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-elements-spring-web-flow-configuration-file
Packt
12 Oct 2009
9 min read
Save for later

The Elements of the Spring Web Flow Configuration File

Packt
12 Oct 2009
9 min read
Let's take a look at the XML Schema Definition (XSD) file of the Spring Web Flow configuration file. To make the file more compact and easier to read, we have removed documentation and similar additions from the file. The complete file is downloadable from http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd. An XSD file is a file that is used to describe an XML Schema, which in itself is a W3C recommendation to describe the structure of XML files. In this kind of definition files, you can describe which elements can or must be present in an XML file. XSD files are primarily used to check the validity of XML files that are supposed to follow a certain structure. The schema can also be used to automatically create code, using code generation tools. The elements of the Spring configuration file are: flow The root element of the Spring Web Flow definition file is the flow element. It has to be present in all configurations because all other elements are sub-elements of the flow tag, which defines exactly one flow. If you want to define more than one flow, you will have to use the same number of flow tags. As every configuration file allows only one root element, you will have to define a new configuration file for every flow you want to define. attribute Using  the attribute tag, you can define metadata for a flow. You can use this metadata to change the behavior of the flow. secured The secured tag is used to secure your flow using Spring Security. The element is defined like this: <xsd:complexType name="secured"> <xsd:attribute name="attributes" type="xsd:string" use="required" /> <xsd:attribute name="match" use="optional"> <xsd:simpleType> <xsd:restriction base="xsd:string"> <xsd:enumeration value="any" /> <xsd:enumeration value="all" /> </xsd:restriction> </xsd:simpleType> </xsd:attribute> </xsd:complexType> If you want to use the secured element, you will have to at least define the attributes attribute. You can use the attributes element to define roles that are allowed to access the flow, for example. The match attribute defines whether all the elements specified in the attributes attribute have to match successfully (all), or if one of them is sufficient (any). persistence-context The persistence-context element enables you to use a persistence provider in your flow definition. This lets you persist database objects in action-states. To use persistence-context tag, you also have to define a data source and configure the persistence provider of your choice (for example, Hibernate or the Java Persistence API) in your Spring application context configuration file. The persistence-context element is empty, which means that you just have to add <persistence-context /> to your flow definition, to enable its features. var The var element can be used to define instance variables, which are accessible in your entire flow. These variables are quite important, so make sure that you are familiar with them. Using var elements, you can define model objects. Later, you can bind these model objects to the forms in your JSP web sites and can store them in a database using the persistence features enabled with the persistence-context element.  Nevertheless, using instance variables is not mandatory, so you do not have to define any, unless required in your flow. The element is defined as shown in the following snippet from the XSD file: <xsd:element name="var" minOccurs="0" maxOccurs="unbounded"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required" /> <xsd:attribute name="class" type="type" use="required" /> </xsd:complexType> </xsd:element> The element has two attributes that are both required. The instance variable you want to define needs a name, so that you can reference it later in your JSP files. Spring Web Flow also needs to know the type of the variable, so you have to define the class attribute with the class of your variable. input You can use the input element to pass information into a flow. When you call a flow, you can (or will have to, depending on whether the input element is required or not) pass objects into the flow. You can then use these objects to process your flow. The XML Schema definition of this element looks like this: <xsd:complexType name="input"> <xsd:attribute name="name" type="expression" use="required" /> <xsd:attribute name="value" type="expression" /> <xsd:attribute name="type" type="type" /> <xsd:attribute name="required" type="xsd:boolean" /> </xsd:complexType> The input element possesses certain attributes, of which only the name attribute is required. You have to specify a name for the input argument, which you can use to reference the variable in your flow. The value attribute is used to specify the value of the attribute, for example, if you want to define a default value for the variable. You can also define a type (for example int or long) for the variable if you want a specific type of information. A type conversion will be tried if the argument passed to the flow does not match the type you expect. With the required attribute, you can control if the user of your flow has to pass in a variable, or if the input attribute is optional. output While you can define input parameters with the input element, you can specify return values with the output element. These are variables that will be passed to your end-state as the result value of your flow. Here's the XML Schema definition of the output element: <xsd:complexType name="output"> <xsd:attribute name="name" type="expression" use="required" /> <xsd:attribute name="value" type="expression" /> <xsd:attribute name="type" type="type" /> <xsd:attribute name="required" type="xsd:boolean" /> </xsd:attribute> </xsd:complexType> The definition is quite similar to the input element. You can also see that the name of the output element is required. Otherwise, you have no means of referencing the variable from your end-state. The value attribute is the value of your variable, for example, the result of a computation or a user returned from a database. Of course, you can also specify the type you expect your output variable to be. As with the input element, a type conversion will be attempted if the type of the variable does not match the type specified here. The required attribute will check if nothing was specified, or the result of a computation is null. If it is null, an error will be thrown.   actionTypes Per se, this is not an element which you can use in your flow definition, but it is a very important part of the XML Schema definition, referenced by many other elements. The definition is quite complex and looks like this: <xsd:group name="actionTypes"> <xsd:choice> <xsd:element name="evaluate"> <xsd:complexType> <xsd:sequence> <xsd:element name="attribute" type="attribute" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> <xsd:attribute name="expression" type="expression" use="required" /> <xsd:attribute name="result" type="expression" use="optional" /> <xsd:attribute name="result-type" type="type" use="optional" /> </xsd:complexType> </xsd:element> <xsd:element name="render"> <xsd:complexType> <xsd:sequence> <xsd:element name="attribute" type="attribute" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> <xsd:attribute name="fragments" type="xsd:string" use="required" /> </xsd:complexType> </xsd:element> <xsd:element name="set"> <xsd:complexType> <xsd:sequence> <xsd:element name="attribute" type="attribute" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> <xsd:attribute name="name" type="expression" use="required" /> <xsd:attribute name="value" type="expression" use="required" /> <xsd:attribute name="type" type="type" /> </xsd:complexType> </xsd:element> </xsd:choice> </xsd:group> actionTypes is a group of sub-elements, namely evaluate, render, and set. Let's go through the single elements to understand how the whole definition works. evaluate With the evaluate element, you can execute code based on the expression languages. As described by the above source code, the element has three attributes; one of them is required. The expression attribute is required and executes the code that you want to run. The result value of the expression, if present, can be stored in the result attribute. Using the result-type attribute, you can convert the result value in the specified type, if needed. Additionally, you can define attributes using a sub-element of the attribute element. render Use the render element to partially render content of a web site. Using the required fragments attribute, you can define which fragments should be rendered. When the link on a web site is clicked the entire web site is not a re-load. Spring JavaScript allows you to update chosen parts of your web page. The remaining web site will not be reloaded, which can greatly enhance the performance of your web application. As is the case with the evaluate element, you can also specify additional attributes using the attribute sub-element. set The set element can be used to set attributes in one of the Spring Web Flows scopes. With the name attribute you can define where (in which scope) you want to define the attribute, and how it should be called. The following short source code illustrates how the set element works: <set name="flowScope.myVariable" value="myValue" type="long" /> As you can see, the name consists of the name of the scope and the name of your variable, delimited by a dot (.). Both the name attribute and the value attribute are required. The value is the actual value of your variable. The type attribute is optional and describes the type of your variable. As before, you can also define additional attributes using the attribute sub-element.
Read more
  • 0
  • 0
  • 2806

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-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-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-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-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-multi-table-query-generator-using-phpmyadmin-and-mysql
Packt
09 Oct 2009
4 min read
Save for later

The Multi-Table Query Generator using phpMyAdmin and MySQL

Packt
09 Oct 2009
4 min read
The Search pages in the Database or Table view are intended for single-table lookups. This article by Marc Delisle, covers the multi-table Query by example (QBE) feature available in the Database view. Many phpMyAdmin users work in the Table view, table-by-table, and thus tend to overlook the multi-table query generator, which is a wonderful feature for fine-tuning queries. The query generator is useful not only in multi-table situations but also for a single table. It enables us to specify multiple criteria for a column, a feature that the Search page in the Table view does not possess. The examples in this article assumes that a multi-user installation of the linked-tables infrastructure has been made and that the book-copy table created during an exercise in the article on Table and Database Operations in PHP is still there in the marc_book database. To access the code used in this article Click Here. To open the page for this feature, we go to the Database view for a specific database (the query generator supports working on only one database at a time) and click on Query. The screenshot overleaf shows the initial QBE page. It contains the following elements: Criteria columns An interface to add criteria rows An interface to add criteria columns A table selector The query area Buttons to update or to execute the query Choosing Tables The initial selection includes all the tables. In this example, we assume that the linked-table infrastructure has been installed into the marc_book database. Consequently, the Field selector contains a great number of fields. For our example, we will work only with the author and book tables: We then click Update Query. This refreshes the screen and reduces the number of fields available in the Field selector. We can always change the table choice later, using our browser's mechanism for multiple choices in drop-down menus (usually, control-click). Column Criteria Three criteria columns are provided by default. This section discusses the options we have for editing their criteria. These include options for selecting fields, sorting individual columns, entering conditions for individual columns, and so on. Field Selector: Single-Column or All Columns The Field selector contains all individual columns for the selected tables, plus a special choice ending with an asterisk (*) for each table, which means all the fields are selected: To display all the fields in the author table, we choose `author`.* and check the Show checkbox, without entering anything in the Sort and Criteria boxes. In our case, we select `author`.`name`, because we want to enter some criteria for the author's name. Sorts For each selected individual column, we can specify a sort (in Ascending or Descending order) or let this line remain intact (meaning no sort). If we choose more than one sorted column, the sort will be done with a priority from left to right. When we ask for a column to be sorted, we normally check the Show checkbox, but this is not necessary because we might want to do just the sorting operation without displaying this column. Showing a Column We check the Show checkbox so that we can see the column in the results. Sometimes, we may just want to apply a criterion on a column and not include it in the resulting page. Here, we add the phone column, ask for a sort on it, and choose to show both the name and phone number. We also ask for a sort on the name in ascending order. The sort will be done first by name, and then by phone number, if the names are identical. This is because the name is in a column criterion to the left of the phone column, and thus has a higher priority:
Read more
  • 0
  • 0
  • 8427
Modal Close icon
Modal Close icon