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

7018 Articles
article-image-enhancing-user-experience-php-5-ecommerce-part-3
Packt
29 Jan 2010
8 min read
Save for later

Enhancing the User Experience with PHP 5 Ecommerce: Part 3

Packt
29 Jan 2010
8 min read
Help! It's out of stock! If we have a product that is out of stock, we need to make it possible for our customers to sign up to be alerted when they are back in stock. If we don't do this, then they will be left with the option of either going elsewhere, or regularly returning to our store to check on the stock levels for that particular product. To try and discourage these customers from going elsewhere a "tell me when it is back in stock" option saves them the need to regularly check back, which would be off-putting. Of course, it is still likely that the customer may go elsewhere; however, if our store is niche, and the products are not available elsewhere, then if we give the customer this option they will feel more valued. There are a few stages involved in extending our framework to support this: Firstly, we need to take into account stock levels. If a product has no stock, we need to insert a new template bit with an "alert me when it is back in stock" form. We need a template to be inserted when this is the case. We then need functionality to capture and store the customer's e-mail address, and possibly their name, so that they can be informed when it is back in stock. Next, we need to be able to inform all of the customers who expressed an interest in a particular product when it is back in stock. Once our customers have been informed of the new stock level of the product, we need to remove their details from the database to prevent them from being informed at a later stage that there are more products in stock. Finally, we will also require an e-mail template, which will be used when sending the e-mail alerts to our customers. Detecting stock levels With customizable products, stock levels won't be completely accurate. Some products may not require stock levels, such as gift vouchers and other non-tangible products. To account for this, we could either add a new field to our database to indicate to the framework that a products stock level isn't required for that particular product, or we could use an extreme or impossible value for the stock level, for example -1 to indicate this. Changing our controller We already have our model set to pull the product stock level from the database; we just need our controller to take this value and use different template bits where appropriate. We could also alter our model to detect stock levels, and if stock is required for a product. if( $productData['stock'] == 0 ){$this->registry->getObject('template')->addTemplateBit( 'stock', 'outofstock.tpl.php' );}elseif( $productData['stock'] > 0 ){$this->registry->getObject('template')->addTemplateBit( 'stock', 'instock.tpl.php' );}else{$this->registry->getObject('template')->getPage()->addTag( 'stock', '' );} This simple code addition imports a template file into our view, depending on the stock level. Out of stock: a new template bit When the product is out of stock, we need a template to contain a form for the user to complete, so that they can register their interest in that product. <h2>Out of stock!</h2><p>We are <strong>really</strong> sorry, but this product is currentlyout of stock. If you let us know your name and email address, wewill let you know when it is back in stock.</p><form action="products/stockalert/{product_path}" method="post"><label for="stock_name">Your name</label><input type="text" id="stock_name" name="stock_name" /><label for="stock_email">Your email address</label><input type="text" id="stock_email" name="stock_email" /><input type="submit" id="stock_submit" name="stock_submit"value="Let me know, when it is back in stock!" /></form> Here we have the form showing our product view, allowing the customer to enter their name and e-mail address: Tell me when it is back in stock please! Once a customer has entered their name, e-mail address, and clicked on the submit button, we need to store these details and associate them with the product. This is going to involve a new database table to maintain the relationship between products and customers who wish to be notified when they are back in stock. Stock alerts database table We need to store the following information in the database to manage a list of customers interested in being alerted when products are back in stock: Customer name Customer e-mail address Product In terms of a database, the following table structure would represent this: Field Type Description ID Integer (Primary Key, Auto Increment) The ID for the stock alert request Customer Varchar The customer's name Email Varchar The customer's e-mail address ProductID Integer The ID of the product the customer wishes to be informed about when it is back in stock The following SQL represents this table: CREATE TABLE `product_stock_notification_requests` (`ID` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,`customer` VARCHAR( 100 ) NOT NULL ,`email` VARCHAR( 255 ) NOT NULL ,`product` INT NOT NULL ,`processed` BOOL NOT NULL ,INDEX ( `product` , `processed` )) ENGINE = INNODB COMMENT = 'Customer notification requests fornew stock levels'ALTER TABLE `product_stock_notification_requests` ADD FOREIGN KEY ( `product` ) REFERENCES `book4`.`content` (`ID`)ON DELETE CASCADE ON UPDATE CASCADE  More controller changes Some modifications are needed to our product's controller to process the customer's form submission and save it in the stock alerts database table. In addition to the following code, we must also change our switch statement to detect that the customer is visiting the stockalert section, and that the relevant function should be called. private function informCustomerWhenBackInStock(){$pathToRemove = 'products/stockalert/';$productPath = str_replace( $pathToRemove, '', $this->registry->getURLPath() );require_once( FRAMEWORK_PATH . 'models/products/model.php');$this->model = new Product( $this->registry, $productPath ); Once we have included the model and checked that the product is valid, all we need to do is build our insert array, containing the customer's details and the product ID, and insert it into the notifications table. if( $this->model->isValid() ){ $pdata = $this->product->getData(); $alert = array(); $alert['product'] = $pdata['ID']; $alert['customer'] = $this->registry->getObject('db')-> sanitizeData( $_POST['stock_name'] ); $alert['email'] = $this->registry->getObject('db')-> sanitizeData( $_POST['stock_email'] ); $alert['processed'] = 0; $this->registry->getObject('db')-> insertRecords('product_stock_notification_requests', $alert ); // We then inform the customer that we have saved their request. $this->registry->getObject('template')->getPage()-> addTag('message_heading', 'Stock alert saved'); $this->registry->getObject('template')->getPage()-> addTag('message_heading', 'Thank you for your interest in this product, we will email you when it is back in stock.'); $this->registry->getObject('template')-> buildFromTemplates('header.tpl.php', 'message.tpl.php', 'footer.tpl.php');} If the product wasn't valid, we tell them that, so they know the notification request was not saved. else{ $this->registry->getObject('template')->getPage()-> addTag('message_heading', 'Invalid product'); $this->registry->getObject('template')->getPage()-> addTag('message_heading', 'Unfortunately, we could not find the product you requested.'); $this->registry->getObject('template')-> buildFromTemplates('header.tpl.php', 'message.tpl.php', 'footer.tpl.php');}} This code is very basic, and does not validate e-mail address formats, something which must be done before we try to send any e-mails out. It is back! Once the product is back in stock, we need to then alert those customers that the product which they were interested in is back in stock, and that they can proceed to make their purchase. This isn't something we can implement now, as we don't have an administrative interface in place yet. However, we can discuss what is involved in doing this: The administrator alters the stock level. Customers interested in that product are looked up. E-mails for each of those customers are generated with relevant details, such as their name and the name of the product being automatically inserted. E-mails are sent to the customers. The database contains a processed field, so once an e-mail is sent, we can set the processed value to 1, and then once we have alerted all of our customers, we can delete those records. This covers us in the unlikely event that all the new stock sells out while we are e-mailing customers, and a new customer completes the notification form.
Read more
  • 0
  • 0
  • 2332

article-image-enhancing-user-experience-php-5-ecommerce-part-2
Packt
29 Jan 2010
6 min read
Save for later

Enhancing the User Experience with PHP 5 Ecommerce: Part 2

Packt
29 Jan 2010
6 min read
Providing wish lists Wish lists allow customers to maintain a list of products that they would like to purchase at some point, or that they would like others to purchase for them as a gift. Creating the structure To effectively maintain wish lists for customers, we need to keep a record of: The product the customer desires The quantity of the product If they are a logged-in customer, their user ID If they are not a logged-in customer, some way to identify their wish-list products for the duration of their visit to the site The date they added the products to their wish list The priority of the product in their wish lists; that is, if they really want the product, or if it is something they wouldn't mind having Let's translate that into a suitable database table that our framework can interact with: Field Type Description ID Integer (Primary Key, Auto Increment) A reference for the database Product Integer The product the user wishes to purchase Quantity Integer The number of them the user would like Date added Datetime The date they added the product to their wish list Priority Integer Relative to other products in their wish list, and how important is this one Session ID Varcharr The user's session id(so they don't need to be logged in) IP Address Varchar The user's IP address (so they don't need to be logged in) By combining the session ID and IP address of the customer, along with the timestamp of when they added the product to their wish list, we can maintain a record of their wish list for the duration of their visit. Of course, they would need to register, or log in, before leaving the site, for their wish list to be permanently saved. This also introduces an element of maintenance to this feature, as once a customer who has not logged in closes their session, their wish-list data cannot be retrieved, so we would need to implement some garbage collection functions to prune this table. The following SQL represents this table: CREATE TABLE `wish_list_products` (`ID` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,`product` INT NOT NULL,`quantity` INT NOT NULL,`user` INT NOT NULL,`dateadded` TIMESTAMP NOT NULLDEFAULT CURRENT_TIMESTAMP,`priority` INT NOT NULL,`sessionID` VARCHAR( 50 ) NOT NULL,`IPAddress` VARCHAR( 50 ) NOT NULL,INDEX ( `product` )) ENGINE = INNODB COMMENT = 'Wish list products'ALTER TABLE `wish_list_products` ADD FOREIGN KEY ( `product` ) REFERENCES `book4`.`content` (`ID`)ON DELETE CASCADE ON UPDATE CASCADE; Saving wishes Now that we have a structure in place for storing wish-list products, we need to have a process available to save them into the database. This involves a link or button placed on the product view, and either some modifications to our product controller, or a wish-list controller, to save the wish. As wish lists will have their own controller and model for viewing and managing the lists, we may as well add the functionality into the wish-list controller. So we will need: a controller a link in our product view Wish-list controller The controller needs to detect if the user is logged in or not; if they are, then it should add products to the user's wish list; otherwise, it should be added to a session-based wish list, which lasts for the duration of the user's session. The controller also needs to detect if the product is valid; we can do this by linking it up with the products model, and if it isn't a valid product, the customer should be informed of this. Let's look through a potential addProduct() method for our wish-list controller. /** * Add a product to a user's wish list * @param String $productPath the product path * @return void */ We first check if the product is valid, by creating a new product model object, which informs us if the product is valid. private function addProduct( $productPath ){// check product path is a valid and active product$pathToRemove = 'wishlist/add/';$productPath = str_replace( $pathToRemove, '',$this->registry->getURLPath() );require_once( FRAMEWORK_PATH . 'models/products/model.php');$this->product = new Product( $this->registry, $productPath );if( $this->product->isValid(){// check if user is logged in or notif( $this->registry->getObject('authenticate')->loggedIn() == true ){//Assuming the user is logged in, we can also store their ID,// so the insert data is slightly different. Here we insert the// wish into the database.$wish = array();$pdata = $this->product->getData();$wish['product'] = $pdata['ID'];$wish['quantity'] = 1;$wish['user'] = $this->registry->getObject('authenticate')->getUserID();$this->registry->getObject('db')->insertRecords('wish_list_products', $wish );// inform the user$this->registry->getObject('template')->getPage()->addTag('message_heading', 'Product added to your wish list');$this->registry->getObject('template')->getPage()->addTag('message_heading', 'A ' . $pdata['name'].' has been added to your wish list');$this->registry->getObject('template')->buildFromTemplates('header.tpl.php', 'message.tpl.php','footer.tpl.php');} The customer isn't logged into the website, so we add the wish to the database, using session and IP address data to tie the wish to the customer. else{// insert the wish$wish = array();$wish['sessionID'] = session_id();$wish['user'] = 0;$wish['IPAddress'] = $_SERVER['REMOTE_ADDR'];$pdata = $this->product->getData();$wish['product'] = $pdata['ID'];$wish['quantity'] = 1;$this->registry->getObject('db')->insertRecords('wish_list_products', $wish );// inform the user$this->registry->getObject('template')->getPage()->addTag('message_heading','Product added to your wish list');$this->registry->getObject('template')->getPage()->addTag('message_heading', 'A ' . $pdata['name'].' has been added to your wish list');$this->registry->getObject('template')->buildFromTemplates('header.tpl.php', 'message.tpl.php','footer.tpl.php');}} The product wasn't valid, so we can't insert the wish, so we need to inform the customer of this. else{// we can't insert the wish, so inform the user$this->registry->getObject('template')->getPage()->addTag('message_heading', 'Invalid product');$this->registry->getObject('template')->getPage()->addTag('message_heading', 'Unfortunately, the product youtried to add to your wish list was invalid, and was notadded, please try again');$this->registry->getObject('template')->buildFromTemplates('header.tpl.php', 'message.tpl.php','footer.tpl.php');}} Add to wish list To actually add a product to our wish list, we need a simple link within our products view. This should be /wishlist/add/product-path. <p><a href="wishlist/add/{product_path}"title="Add {product_name} to your wishlist">Add to wishlist.</a></p> We could encase this link around a nice image if we wanted, making it more user friendly. When the user clicks on this link, the product will be added to their wish list and they will be informed of that.
Read more
  • 0
  • 0
  • 2551

article-image-instructional-material-using-moodle-19-part-1
Packt
29 Jan 2010
8 min read
Save for later

Instructional Material using Moodle 1.9: Part 1

Packt
29 Jan 2010
8 min read
Selecting and organizing the material If you're like most instructors, you love your subject and the idea of sharing information gives you great satisfaction. However, you have probably noticed that it's easy to overload your students, or to give them materials in a way that tends to confuse them. How can you avoid overloading and confusing your students? One of the most effective ways to do so is to make sure that you base your selections of instructional materials on course outcomes and on the learning objectives for each unit. Keep in mind what you'd like your students to be able to do after they complete the course. What is the basic, enduring knowledge they will take with them after the course is over? What kind of fundamental change do you want to occur in terms of the student's abilities? What kind of new skills will they be able to perform? Once you answer these questions, you will have a list of learning outcomes. Keep them in mind as you select the instructional material you wish to use in your course. It is often convenient to develop a map or a diagram that connects your learning outcomes with the course materials and the assessments you will use. Consider what you want your students to learn, and how you'd like them to perform. Also, you shape the sequence you will build and how you'll present the materials. It is often convenient to develop a map or a diagram that connects your learning outcomes with the course materials and the assessments you will use. Consider what you want your students to learn, and how you'd like them to perform. Also, you shape the sequence you will build and how you'll present the materials. Using forums to present your material We'll start with an approach that is very easy to implement, which is ideal if you're just getting started and need a solution that would be good for all kinds of e-learning, including mobile learning and guided independent study. Basically, we'll use the Forum tool to organize all the instructional content. In Moodle, the Forum is the key tool and you'll use it often. Later, as you feel more comfortable, you can add more tools (Book, Chat, Assignment, Choice, and so on). For now, however, we will focus on getting you operational as quickly and easily as possible. Using the Forum tool to structure your course and to organize your content is conceptually very elegant. Students simply move from forum to forum, and they access the material they need. Any comments they have, writing assignments, or discussion items can be completed in the appropriate thread. When you use the Forum tool, you will use the Moodle text editor to create messages. Keep in mind that your messages can contain text, graphics, audio, video, presentations, and more, which allows you flexibility and ease of use. As you plan your course, it's always good to have a certain number of forums dedicated to student success and support. This is where you can post welcome messages, timelines and course calendars, lists of assignments, syllabus, links to useful resources, and a place for students to ask questions and share their experiences. A key student success forum is one that clearly states what you hope to achieve in the course. By listing course outcomes in a separate forum, you'll shape the students' approach to the course content, and they will have a better idea of how to organize the information they will encounter. After you've developed your "student success and support" forums, you start creating a separate forum for each unit, which begins to identify the learning objectives, and the resources you'll put in each one to create a learning environment. It is often a good idea to create a separate forum for each graded assessment. Having a separate forum for each assessment will make your job easier if you have changes to make, or if you want to replace it with an assignment tool. In fact, by populating your course with a series of separate forums, you are creating a flexible template that can be easily modified by replacing a forum with another, or with a different type of tool (Choice, Assignment, Chat, Database, Book, Journal, or more). It is often helpful to create a course map wherein you draw all the elements you'll have in your course. List the course outcomes, and then map each one to the instructional material, activities, and assessments that go with each one. This will help you as you start building your forums. Here is an example of how you can put together a course in which you organize the content around forums: Forum 1: Welcome and Course Overview and Objectives Forum 2: Meet Your Instructor Forum 3: Introduce Yourself Forum 4: Questions for the Instructor Forum 5: Syllabus and Timeline Forum 6: Unit 1: Unit Learning Objectives, Instructional Materials, and Discussion Questions Forum 7: Unit 1: Review for Quiz Forum 8: Unit 1: Quiz Forum 9: Unit 1: Instructional Materials and Discussion Questions As you can see, the structure is very straightforward and avoids the complexity of multiple tools. Keep in mind that more complex tools can always be added later to replace a forum structure. Creating a separate group for each student Start by selecting the activity tool, Forum, and opening a page that requires you to indicate the settings for the forum you wish to add. Remember that each group will consist of only a single student. So, in this process, when we discuss groups, we're really talking about individuals. The following steps illustrate how to create a separate forum for each group in your course: From the Add an activity… drop-down list, select Forum, as shown in the following screenshot: Enter a Forum name and Forum type for the forum. In the following example, I'm using A single simple discussion to create a single-topic forum, where all the postings will be displayed on the same page. This makes the history of the student-teacher discussion very easy to see. This type of forum is most useful for short, focused discussions. By selecting Yes, forever for Force everyone to be subscribed? as shown in the following screenshot, you ensure that all students are subscribed automatically, even students that enroll at a later time. The key setting here is Group mode. When we select Separate groups, we create a separate forum for each group in the class. In the next section, we will create a group for each student. The result is a separate forum for each student, available only to that student and the teacher, where they can hold private conversation. Save the forum settings and continue. Enrolling students If you have not already enrolled students in the course, you should do so before creating the groups. If the students are already enrolled, move to Create a Group for Each Student in the next section. The following steps illustrate how to manually enroll students in your course: Open the course into which you want to enroll the students. Then, from the Administration drop-down box, select Assign roles as shown in the following screenshot: On the Assign roles page select Student, as shown in the following screenshot: Ensure the Role to assign drop-down list is set to Student. Then from the list of potential users on the right, select one user. Click the left-facing arrow to enrol that user in your course (refer to the following screenshot): Repeat this for each student. If you want to remove a student from the course, select the student from the list on the left, and click the right-facing arrow. To exit this page, select the course name from the navigation breadcrumbs at the top of the page. This will put you back into your course's home page, and then you can continue with creating a group for each student. Creating a group for each student After all of your students are enrolled, go into the course and create a group for each student. The following steps illustrate how to create groups and assign students to them: From the Administration block select Groups, as shown in the following screenshot: From the Current role drop-down list as shown in the following screenshot, select Student. This ensures that you are seeing only users who are enrolled as students in this course. Then, in the field above the Add new group button, enter the name of the first group. Name the group after the student for whom you created it. In this example, I created a group for Moodle Student1 called Student1, and I am about to create a group for Moodle Student2 called Student2. After creating all of the groups, add one student to each group. In the following example, you can see that the group Student1 is selected, and Moodle Student1 is a member of that group. Select the group. In the preceding example, you can see the user is about to select the group Student2. Select the student to add to the group. Click the Add selected to group button. Repeat as needed. To assign a student to a group:   To exit this page, select the course name from the navigation breadcrumbs at the top of the page. This will put you back into your course's home page. The student's private forum will look like any other Moodle forum. However, only the student and teacher will have access to it.
Read more
  • 0
  • 0
  • 1214

article-image-shipping-modules-magento-part-2
Packt
29 Jan 2010
8 min read
Save for later

Shipping Modules in Magento: Part 2

Packt
29 Jan 2010
8 min read
Appearing in the administration Once this has been done, the shipping method should appear in Shipping Methods under System->Configuration: Now, we will look at the most useful shipping module fields that are used when putting the shipping module together. These are fields with predefined names and types that have automatically processed the results that they output. Therefore, they require no additional coding in the adaptor module to take them on board; Magento performs these methods straight out of the box. Free shipping If we want to enable an automatic price-based amount for free shipping with our method, we can add in a field called free_shipping_enable and combine this with another field by the name of free_shipping_subtotal. When free_shipping_enable is set to Enabled by the Magento administrator, then Magento will automatically take free_shipping_subtotal into account and offer free shipping if the total amount is above the value of free_shipping_subtotal. If this field is disabled, Magento will simply process using the default shipping calculation behavior of the module.   The fields are set up as follows, with sort_order and show_in_ values varying: <free_shipping_enable translate="label"> <label>Free shipping with minimum order amount</label> <frontend_type>select</frontend_type> <source_model>adminhtml/system_config_source_enabledisable</source_model> <sort_order>21</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store></free_shipping_enable><free_shipping_subtotal translate="label"> <label>Minimum order amount for free shipping</label> <frontend_type>text</frontend_type> <sort_order>22</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store></free_shipping_subtotal> Handling Handling charges sometimes come into the equation and need to be added onto the overall transaction. Magento enables us to do this using the following source models to present what we want to achieve: <handling_type translate="label"> <label>Calculate Handling Fee</label> <frontend_type>select</frontend_type> <source_model>shipping/source_handlingType</source_model> <sort_order>10</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store></handling_type><handling_action translate="label"> <label>Handling Applied</label> <frontend_type>select</frontend_type> <source_model>shipping/source_handlingAction</source_model> <sort_order>11</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store></handling_action><handling_fee translate="label"> <label>Handling fee</label> <frontend_type>text</frontend_type> <sort_order>12</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store></handling_fee> Restricting a shipping method to certain countries This will allow us to present the option to the administrator for filtering the shipping method to be only accessible to certain countries. In practice, this means that if we wanted to offer only one type of delivery to the United Kingdom, then we could do so simply by selecting United Kingdom from the multi-select field created by the following declaration. The Magento administrator can choose the specific countries from the multiple select list. Only orders from those countries that we have created shipping methods for will be processed in the shipping module. This enables them to choose any number of countries for restricting this shipping method to . sallowspecific translate="label"> <label>Ship to applicable countries</label> <frontend_type>select</frontend_type> <sort_order>90</sort_order> <frontend_class>shipping-applicable-country</frontend_class><source_model>adminhtml/system_config_source_shipping_allspecificcountries</source_model> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store></sallowspecific><specificcountry translate="label"> <label>Ship to Specific countries</label> <frontend_type>multiselect</frontend_type> <sort_order>91</sort_order><source_model>adminhtml/system_config_source_country</source_model> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store></specificcountry><showmethod translate="label"> <label>Show method if not applicable</label> <frontend_type>select</frontend_type> <sort_order>92</sort_order><source_model>adminhtml/system_config_source_yesno</source_model> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store></showmethod> Using our template to create a shipping method Now that we have our bare-bones shipping module, we continue with the creation of something that we can see an outcome from. From this we should be able to start to put together our own shipping module tailor-made for future needs. The purpose of what we are going to build is going to be very simple: we're going to create a shipping module that meets the following parameters: It has a handling fee, either per product or for the entire order It can be limited to specific countries It can set a simple flat-rate shipping cost, if 10 products or more are being ordered It can set another simple flat-rate shipping cost, if 10 products or less are being ordered All of the above can be configured via the Magento administration Before progressing, we delete the previous shipping module from our installation to make sure that it does not interfere with what we'll be building. To do this, we go back to the Magento Downloader  and select Uninstall from the module's supporting dropdown before committing the changes. The configuration files This time, we'll go with the directory MagentoBook and the name FullShippingModule. For this, our /app/code/local/MagentoBook/ShippingModule/MagentoBook/FullShippingModule/etc/config.xml file will look like: <?xml version="1.0"?><config> <modules> <MagentoBook_FullShippingModule> <version>0.1.0</version> <depends> <Mage_Shipping /> </depends> </MagentoBook_FullShippingModule></modules><global> <models> <FullShippingModule> <class>MagentoBook_FullShippingModule_Model</class> </FullShippingModule> </models><resources> <fullshippingmodule_setup> <setup> <module>MagentoBook_FullShippingModule</module> </setup> <connection> <use>core_setup</use> </connection> </fullshippingmodule_setup> </resources> </global></config> We turn on FullShippingModule, and allow it to be turned off/on from within the administration. Then, we create /app/etc/modules/MagentoBook_FullShippingModule.xml and place the following in it: <?xml version="1.0"?><config> <modules> <MagentoBook_FullShippingModule> <active>true</active> <codePool>local</codePool> </MagentoBook_FullShippingModule> </modules></config> Our adaptor For those interested in cutting down on code, unnecessary comments have been removed (which were included in the previous adaptor in this article). We place the following code in: /app/code/local/MagentoBook/FullShippingModule/Model/Carrier/FullBoneMethod.php <?phpclass MagentoBook_FullShippingModule_Model_Carrier_FullBoneMethodextends Mage_Shipping_Model_Carrier_Abstract{ protected $_code = 'fullshippingmodule'; public function collectRates(Mage_Shipping_Model_Rate_Request $request) { if (!$this->getConfigData('active')) { Mage::log('The '.$this->_code.' shipping method is not active.'); return false; } $handling = $this->getConfigData('handling'); $result = Mage::getModel('shipping/rate_result'); $method = Mage::getModel('shipping/rate_result_method'); $items = Mage::getModel('checkout/session')->getQuote()- >getAllItems(); if (count($items) >= $this->getConfigData('minimum_item_limit')) { $code = $this->getConfigData('over_minimum_code'); $title = $this->getConfigData('over_minimum_title'); $price = $this->getConfigData('over_minimum_price'); } else { $code = $this->getConfigData('under_minimum_code'); $title = $this->getConfigData('under_minimum_title'); $price = $this->getConfigData('under_minimum_price'); } $method->setCarrier($this->_code); $method->setCarrierTitle($this->getConfigData('title')); $method->setMethod($code); $method->setMethodTitle($title); $method->setPrice($price + $handling); $result->append($method); return $result; }} In short, this will check whether there are more items in the cart than the pre-configured value of minimum_item_limit and then apply a rate if it is over the set limit. If under the limit, it applies another rate.
Read more
  • 0
  • 0
  • 1444

article-image-media-file-management-joomla-ftp-and-third-party-extensions
Packt
29 Jan 2010
5 min read
Save for later

Media File management in Joomla with FTP and Third-party Extensions

Packt
29 Jan 2010
5 min read
Alternative method of managing files and media Depending on your circumstances, you may or may not have login access to your web hosting server. If you do not, then one of your only options for uploading files will be to use the Joomla! Media Manager, or the option of third-party Joomla! Extensions. If you do have web server access, then by using a method called FTP (File Transfer Protocol), you will be able to gain greater control over your file management. FTP is a standard network protocol that is used to exchange and manipulate files over a computer network. A common use of FTP is to transfer files over the Internet between a local computer and a web server, which is exactly what we are after! FTP clients There are numerous FTP clients (programs) that can be used to transfer files. Some of these graphically show the file and transfer processes, making the management of your files from your computer to your web server very easy to do. FTP programs FTP programs range from no cost applications through to commercial software. Which one you choose to use will be down to personal preference. Most of these programs provide drag and drop features as well as easy directory navigation tools: There are excellent FTP programs for all major operating systems. Some popular options for Windows and Mac are: Windows FileZilla CuteFTP SmartFTP WS_FTP cURL Mac FileZilla Transmit Cyberduck CuteFTP Fetch FTP Comm and in Terminal If you perform a search using a popular search engine, you will obtain a definitive list of FTP programs. A suggestion would be to download a trial version of these to see which one suits your operating system and requirements. For the purpose of this topic, I have chosen to use and take screenshots from an FTP program called "Transmit". It is a commercial product, but personally one of my favorites. For those whose use MAC computers, Transmit is recognized as a wonderful FTP tool. Connecting using an FTP program Almost all FTP programs require similar information in order to connect to the web server. Depending on the program you are using, the naming of these fields may be slightly different. In order to connect, we need the following information which is usually derived from setting up a user account (with FTP permissions) on your web hosting control panel: Server This is the server address that you wish to connect to. Typically this can look like ftp.yourserver.com. Depending on the domain name settings, it can sometimes be your domain name, such as www.yourserver.com. User Name This is your web server account username. Often this can be in the format of yourusername@yourdomain.com. Password This is your web server account password. Initial Path Some programs offer the ability to set an initial directory to navigate to upon login. If you do not have this option, then do not worry. Port If the server requires connections on a port other than the default one, some programs offer you the ability to enter in a port number. It is best to leave this as the default setting unless you know what you are doing. If you are having any issues connecting, then it's best to contact your web hosting administrator in order to check your login access details. There are typically three types of FTP login methods available. These are: Anonymous FTP access This is an easy connection method as you do not need to include any user information. Sometimes software companies offer updates or corporate and government websites offer forms and content to be downloaded via an anonymous connection method. Username A simplified but restricted access level where you will be required to enter just a username. This type of FTP login is often used in school and intranet environments. Username and Password This is a more restricted security access level where the user requires both a username and password in order to access the server. This method is often used by web hosting companies who offer people the ability to upload files to the web server. If your FTP connection is set to username (or username and password), then you should see a dialog box on the screen. This will prompt you to enter your security access details: Once connected, you will need to navigate to your webroot folder. Depending on your web server, this area may be named httpdocs, mainwebsite_html, public_html, or other naming conventions. It will be inside this directory where your Joomla! website files will reside. When you have located your main http documents area and clicked to navigate inside this, you will see the default Joomla! media folder named images. When you have successfully navigated to your remote main media folder (or any of the subfolders within this), you will need to make sure that you also navigate locally to the folders or files you wish to upload. Most FTP programs offer you the ability to create new directories, and drag and drop files from your local computer to the web server. By using an FTP program, you can gain additional control over your website files and content. FTP programs can allow you to: Create files and directories Rename files and directories Move files and directories Delete files and directories Set file and directory permissions FTP programs offer you the most flexibility in managing your website files, but it is important to take care when using FTP programs. By connecting to your directory structure on the web server, you are navigating amongst core Joomla! files.
Read more
  • 0
  • 0
  • 4428

article-image-embedding-doctests-python-docstrings
Packt
29 Jan 2010
12 min read
Save for later

Embedding Doctests in Python Docstrings

Packt
29 Jan 2010
12 min read
Doctests aren't confined to simple text files. You can put doctests into Python's docstrings. Why would you want to do that? There are a couple of reasons. First of all, docstrings are an important part of the usability of Python code (but only if they tell the truth). If the behavior of a function, method, or module changes and the docstring doesn't get updated, then the docstring becomes misinformation, and a hindrance rather than a help. If the docstring contains a couple of doctest examples, then the out-of-date docstrings can be located automatically. Another reason for placing doctest examples into docstrings is simply that it can be very convenient. This practice keeps the tests, documentation and code all in the same place, where it can all be located easily. If the docstring becomes home to too many tests, this can destroy its utility as documentation. This should be avoided; if you find yourself with so many tests in the docstrings that they aren't useful as a quick reference, move most of them to a separate file. Time for action – embedding a doctest in a docstring We'll embed a test right inside the Python source file that it tests, by placing it inside a docstring. Create a file called test.py with the following contents: def testable(x): r""" The `testable` function returns the square root of its parameter, or 3, whichever is larger. >>> testable(7) 3.0 >>> testable(16) 4.0 >>> testable(9) 3.0 >>> testable(10) == 10 ** 0.5 True """ if x < 9: return 3.0 return x ** 0.5 At the command prompt, change to the directory where you saved test.py and then run the tests by typing: $ python -m doctest test.py As mentioned earlier before, if you have an older version of Python, this isn't going to work for you. Instead, you need to type python -c "__import__('doctest').testmod(__import__('test'))" If everything worked, you shouldn't see anything at all. If you want some confirmation that doctest is doing something, turn on verbose reporting by changing the command to: python -m doctest -v test.py For older versions of Python, instead use python -c "__import__('doctest').testmod(__import__('test'), verbose=True)" What just happened You put the doctest right inside the docstring of the function it was testing. This is a good place for tests that also show a user how to do something. It's not a good place for detailed, low-level tests (the above example, which was quite detailed for illustrative purposes, is skirting the edge of being too detailed), because docstrings need to serve as API documentation. You can see the reason for this just by looking back at the example, where the doctests take up most of the room in the docstring, without telling the readers any more than they would have learned from a single test. Any test that will serve as good API documentation is a good candidate for including in the docstrings. Notice the use of a raw string for the docstring (denoted by the r character before the first triple-quote). Using raw strings for your docstrings is a good habit to get into, because you usually don't want escape sequences—e.g. n for newline—to be interpreted by the Python interpreter. You want them to be treated as text, so that they are correctly passed on to doctest. Doctest directives Embedded doctests can accept exactly the same directives as doctests in text files can, using exactly the same syntax. Because of this, all of the doctest directives that we discussed before can also be used to aff ect the way embedded doctests are evaluated. Execution scope Doctests embedded in docstrings have a somewhat different execution scope than doctests in text files do. Instead of having a single scope for all of the tests in the file, doctest creates a single scope for each docstring. All of the tests that share a docstring, also share an execution scope, but they're isolated from tests in other docstrings. The separation of each docstring into its own execution scope often means that we don't need to put much thought into isolating doctests, when they're embedded in docstrings. That is fortunate, since docstrings are primarily intended for documentation, and the tricks needed to isolate the tests might obscure the meaning. Putting it in practice: an AVL tree We'll walk step-by-step through the process of using doctest to create a testable specification for a data structure called an AVL Tree. An AVL tree is a way to organize key-value pairs, so that they can be quickly located by key. In other words, it's a lot like Python's built-in dictionary type. The name AVL references the initials of the people who invented this data structure. As its name suggests, an AVL tree organizes the keys that are stored in it into a tree structure, with each key having up to two child keys—one child key that is less than the parent key by comparison, and one that is more. In the following picture, the key Elephant has two child keys, Goose has one, and Aardvark and Frog both have none. The AVL tree is special, because it keeps one side of the tree from getting much taller than the other, which means that users can expect it to perform reliably and efficiently no matter what. In the previous image, an AVL tree would reorganize to stay balanced if Frog gained a child. We'll write tests for an AVL tree implementation here, rather than writing the implementation itself. Therefore, we'll elaborate over the details of how an AVL tree works, in favor of looking at what it should do when it works right If you want to know more about AVL Trees, you will find many good references on the Internet. Wikipedia's entry on the subject is a good place to start with:http://en.wikipedia.org/wiki/AVL_tree. We'll start with a plain language specification, and then interject tests between the paragraphs. You don't have to actually type all of this into a text file; it is here for you to read and to think about. English specification The first step is to describe what the desired result should be, in normal language. This might be something that you do for yourself, or something that somebody else does for you. If you're working for somebody, hopefully you and your employer can sit down together and work this part out. In this case, there's not much to work out, because AVL Trees have been fully described for decades. Even so, the description here isn't quite like one you'd find anywhere else. This capacity for ambiguity is exactly the reason why a plain language specification isn't good enough. We need an unambiguous specification, and that's exactly what the tests in a doctest file can give us. The following text goes in a file called AVL.txt, (which you can find in its final form in the accompanying code archive. At this stage of the process, the file contains only the normal language specification.): An AVL Tree consists of a collection of nodes organized in a binarytree structure. Each node has left and right children, each of whichmay be either None or another tree node. Each node has a key, whichmust be comparable via the less-than operator. Each node has a value.Each node also has a height number, measuring how far the node is frombeing a leaf of the tree -- a node with height 0 is a leaf.The binary tree structure is maintained in ordered form, meaning thatof a node's two children, the left child has a key that comparesless than the node's key and the right child has a key that comparesgreater than the node's key.The binary tree structure is maintained in a balanced form, meaningthat for any given node, the heights of its children are either thesame or only differ by 1.The node constructor takes either a pair of parameters representinga key and a value, or a dict object representing the key-value pairswith which to initialize a new tree.The following methods target the node on which they are called, andcan be considered part of the internal mechanism of the tree:Each node has a recalculate_height method, which correctly sets theheight number.Each node has a make_deletable method, which exchanges the positionsof the node and one of its leaf descendants, such that the the treeordering of the nodes remains correct.Each node has rotate_clockwise and rotate_counterclockwise methods.Rotate_clockwise takes the node's right child and places it wherethe node was, making the node into the left child of its own formerchild. Other nodes in the vicinity are moved so as to maintainthe tree ordering. The opposite operation is performed by rotate_counterclockwise.Each node has a locate method, taking a key as a parameter, whichsearches the node and its descendants for a node with the specifiedkey, and either returns that node or raises a KeyError.The following methods target the whole tree rooted at the currentnode. The intent is that they will be called on the root node:Each node has a get method taking a key as a parameter, which locatesthe value associated with the specified key and returns it, or raisesKeyError if the key is not associated with any value in the tree.Each node has a set method taking a key and a value as parameters, andassociating the key and value within the tree.Each node has a remove method taking a key as a parameter, andremoving the key and its associated value from the tree. It raisesKeyError if no values was associated with that key. Node data The first three paragraphs of the specification describe the member variables of a AVL tree node, and tell us what the valid values for the variables are. They also tell us how tree height should be measured and define what a balanced tree means. It's our job now to take up those ideas, and encode them into tests that the computer can eventually use to check our code. We could check these specifications by creating a node and then testing the values, but that would really just be a test of the constructor. It's important to test the constructor, but what we really want to do is to incorporate checks that the node variables are left in a valid state into our tests of each member function. To that end, we'll define a function that our tests can call to check that the state of a node is valid. We'll define that function just after the third paragraph: Notice that this test is written as if the AVL tree implementation already existed. It tries to import an avl_tree module containing an AVL class, and it tries to use the AVL class is specific ways. Of course, at the moment there is no avl_tree module, so the test will fail. That's as it should be. All that the failure means is that, when the ti me comes to implement the tree, we should do so in a module called avl_tree, with contents that function as our test assumes. Part of the benefit of testing like this is being able to test-drive your code before you even write it. >>> from avl_tree import AVL>>> def valid_state(node):... if node is None:... return... if node.left is not None:... assert isinstance(node.left, AVL)... assert node.left.key < node.key... left_height = node.left.height + 1... else:... left_height = 0...... if node.right is not None:... assert isinstance(node.right, AVL)... assert node.right.key > node.key... right_height = node.right.height + 1... else:... right_height = 0...... assert abs(left_height - right_height) < 2... node.key < node.key... node.value>>> def valid_tree(node):... if node is None:... return... valid_state(node)... valid_tree(node.left)... valid_tree(node.right) Notice that we didn't actually call those functions yet. They aren't tests, per se, but tools that we'll use to simplify writing tests. We define them here, rather than in the Python module that we're going to test, because they aren't conceptually part of the tested code, and because anyone who reads the tests will need to be able to see what the helper functions do. Constructor The fourth paragraph describes the constructor for an AVL node: The node constructor takes either a pair of parameters representing a key and a value, or a dict object representing the key-value pairs with which to initialize a new tree. The constructor has two possible modes of operation: it can either create a single initialized node or it can create and initialize a whole tree of nodes. The test for the single node mode is easy: >>> valid_state(AVL(2, 'Testing is fun')) The other mode of the constructor is a problem, because it is almost certain that it will be implemented by creating an initial tree node and then calling its set method to add the rest of the nodes. Why is that a problem? Because we don't want to test the set method here: this test should be focused entirely on whether the constructor works correctly, when everything it depends on works. In other words, the tests should be able to assume that everything outside of the specific chunk of code being tested works correctly. However, that's not always a valid assumption. So, how can we write tests for things that call on code outside of what's being tested? There is a solution for this problem. For now, we'll just leave the second mode of operation of the constructor untested.
Read more
  • 0
  • 0
  • 12494
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-instructional-material-using-moodle-19-part-2
Packt
29 Jan 2010
6 min read
Save for later

Instructional Material using Moodle 1.9: Part 2

Packt
29 Jan 2010
6 min read
Keeping discussions on track One of the biggest challenges in using forums for an online class is keeping discussions focused on the topic. This becomes even more difficult when you allow students to create new topics in a forum. Moodle offers two tools that you can use to help keep discussions on track—custom scales and splitting discussions. Use a custom scale to rate relevance Moodle enables you to use a scale to rate student's work. A scale offers you something other than a grade to give the student as feedback. Scales can be used to rate forum postings, assignment submissions, and glossary entries. The following screenshot shows a feedback on the relevance of a posting, given in a custom scale by a teacher: To create and apply a custom scale, follow these steps: Users with the roles Administrator, Course creator, and Teacher can create custom scales. From the Administration block, click on Scales. This displays the Scales page. On the Scales page, click on the Add a new scale button. This displays the Editing scale page. On the Editing scale page: Enter a Name for the scale. When you apply the scale to the forum, you will select the scale by this name. In the Scale box, enter the items on your scale. Separate each item with a comma. Write a Description for your scale. Students can see the description, so use this space to explain how they should interpret the scale. Select the Save changes button. You are now ready to apply the scale. Create or edit the forum to which you want to apply the scale. The key setting on the Editing Forum page is Allow posts to be rated? When you review the student postings in the forum, you can rate each posting using the scale you created, as shown in the following screenshot: When you finish rating the postings, click on the Send in my ratings button at the bottom of the page to save your ratings. Split discussions Users with the role Administrator, Course creator, or Teacher can split a discussion. When you split a discussion at a post, the selected post and the ones below become a new topic. Note that you cannot take a few posts from the middle of a topic and split them into a new discussion. Splitting takes every post that is nested below the selected one and puts it into a new topic. Before the split   After the split   Topic 1              Reply 1-1              Reply 1-2                       Reply 1-2-1                       Reply 1-2-2                       Reply 1-2-3              Reply 1-3              Reply 1-4                       Reply 1-4-1                       Reply 1-4-2    New Topic 1-2               Reply 1-2-1               Reply 1-2-2               Reply 1-2-3  Topic 1                Reply 1-1                Reply 1-3                Reply 1-4                           Reply 1-4-1                Reply 1-4-2   Will splitting change the meaning Splitting a thread can rescue a conversation that has gotten off topic. However, it can also change the meaning of the conversation in ways that you don't expect or want. Note that in the preceding example, after the split, the new topic is moved to the top of the forum. Will that change the meaning of your forum? Let's look at an example. Following is the screenshot showing the fi rst topic in a forum on the October Revolution of Russian history. In this topic, students discuss whether the revolution was a coup or a popular uprising: The teacher made the first posting and several students have posted replies. Some of these replies, as shown in the following screenshot, favor the theory that the revolution was a coup, while others favor the theory of revolution being a popular uprising: Note that the posting by Student2 is a reply(Re) to the posting by Student1. You might have missed that because the reply is not indented. That's because the teacher has selected Display replies flat, with oldest first. If the teacher had selected Display replies in nested form, you would see Student2's reply indented, or nested, under Student1's reply. We can tell that Student2 is replying to Student1 because the subject line indicates it is a reply to Student1 (Re: My vote: popular uprising). The first two postings are pro-uprising. The last posting is pro-coup. It occurs to the teacher that it would facilitate discussion to split the forum into pro-uprising and pro-coup topics. The teacher scrolls down to the pro-coup posting, which just happens to be the last posting in this forum, and clicks on Split, as shown in following screenshot: This will make a new topic out of the pro-coup posting: Will splitting move replies you want to keep in place In this example, the teacher was lucky. Under the pro-coup posting, there were no pro-uprising replies. If there were, those replies would have come with the pro-coup posting, and the teacher would not have been able to make a topic that was completely pro-coup.
Read more
  • 0
  • 0
  • 3598

article-image-methods-animation-effects-jquery-14
Packt
29 Jan 2010
6 min read
Save for later

Methods for Animation Effects with jQuery 1.4

Packt
29 Jan 2010
6 min read
Some of the examples in this article use the $.print() function to print results to the page. Pre-packaged effects These methods allow us to quickly apply commonly-used effects with a minimum of configuration. .show() Display the matched elements. .show([duration][, callback]) Parameters duration (optional): A string or number determining how long the animation will run callback (optional): A function to call once the animation is complete Return value The jQuery object, for chaining purposes. Description With no parameters, the .show() method is the simplest way to display an element. $('.target').show(); The matched elements will be revealed immediately with no animation. This is roughly equivalent to calling .css('display', 'block'), except that the display property is restored to whatever it was initially. If an element has a display value of inline, then is hidden and shown, it will once again be displayed inline. When a duration is provided, .show() becomes an animation method. The .show() method animates the width, height, and opacity of the matched elements simultaneously. Durations are given in milliseconds; higher values indicate slower animations, not faster ones. The 'fast' and 'slow' strings can be supplied to indicate durations of 200 and 600 milliseconds, respectively. If supplied, the callback is fired once the animation is complete. This can be useful for stringing different animations together in sequence. The callback is not sent any arguments, but this is set to the DOM element being animated. If multiple elements are animated, it is important to note that the callback is executed once per matched element, not once for the animation as a whole. We can animate any element, such as a simple image: <div id="clickme">Click here</div><img id="book" src="book.png" alt="" width="100" height="123" /> With the element initially hidden, we can show it slowly. $('#clickme').click(function() {$('#book').show('slow', function() {$.print('Animation complete.');});}); .hide() Hide the matched elements. .hide([duration][, callback]) Parameters duration (optional): A string or number determining how long theanimation will run callback (optional): A function to call once the animation is complete Return value The jQuery object, for chaining purposes. Description With no parameters, the .hide() method is the simplest way to hide an element. $('.target').hide(); The matched elements will be hidden immediately, with no animation. This is roughly equivalent to calling .css('display', 'none'), except that the value of the display property is saved in jQuery's data cache so that display can later be restored to its initial value. If an element has a display value of inline, and then is hidden and shown, it will once again be displayed inline. When a duration is provided, .hide() becomes an animation method. The .hide() method animates the width, height, and opacity of the matched elements simultaneously. When these properties reach 0, the display style property is set to none to ensure that the element no longer affects the layout of the page. Durations are given in milliseconds; higher values indicate slower animations, not faster ones. The 'fast' and 'slow' strings can be supplied to indicate durations of 200 and 600 milliseconds, respectively. If supplied, the callback is fired once the animation is complete. This can be useful for stringing different animations together in sequence. The callback is not sent any arguments, but this is set to the DOM element being animated. If multiple elements are animated, it is important to note that the callback is executed once per matched element, not once for the animation as a whole. We can animate any element, such as a simple image: <div id="clickme">Click here</div><img id="book" src="book.png" alt="" width="100" height="123" /> With the element initially shown, we can hide it slowly. $('#clickme').click(function() {$('#book').hide('slow', function() {$.print('Animation complete.');});}); .toggle() Display or hide the matched elements. .toggle([duration][, callback]).toggle(showOrHide) Parameters (first version) duration (optional): A string or number determining how long the animation will run callback (optional): A function to call once the animation is complete Parameters (second version) showOrHide: A Boolean indicating whether to show or hide the elements Return value The jQuery object , for chaining purposes. Description With no parameters, the .toggle() method simply toggles the visibility of elements: $('.target').toggle(); The matched elements will be revealed or hidden immediately with no animation. If the element is initially displayed, it will be hidden; if hidden, it will be shown. The display property is saved and restored as needed. If an element has a display value of inline, then is hidden and shown, it will once again be displayed inline. When a duration is provided, .toggle() becomes an animation method. The .toggle() method animates the width, height, and opacity of the matched elements simultaneously. When these properties reach 0 after a hiding animation, the display style property is set to none to ensure that the element no longer affects the layout of the page. Durations are given in milliseconds; higher values indicate slower animations, not faster ones. The 'fast' and 'slow' strings can be supplied to indicate durations of 200 and 600 milliseconds, respectively. If supplied, the callback is fired once the animation is complete. This can be useful for stringing different animations together in sequence. The callback is not sent any arguments, but this is set to the DOM element being animated. If multiple elements are animated, it is important to note that the callback is executed once per matched element, not once for the animation as a whole. We can animate any element, such as a simple image: <div id="clickme">Click here</div><img id="book" src="book.png" alt="" width="100" height="123" /> We will cause .toggle() to be called when another element is clicked. $('#clickme').click(function() {$('#book').toggle('slow', function() {$.print('Animation complete.');});}); With the element initially shown, we can hide it slowly with the first click: A second click will show the element once again: The second version of the method accepts a Boolean parameter. If this parameter is true, then the matched elements are shown; if false, the elements are hidden. In essence, the following statement $('#foo').toggle(showOrHide); is equivalent to: if (showOrHide) {$('#foo').show();}else {$('#foo').hide();} There is also an event method named .toggle().
Read more
  • 0
  • 0
  • 2512

article-image-migrating-mysql-table-using-oracle-sql-developer-15
Packt
29 Jan 2010
4 min read
Save for later

Migrating a MySQL table using Oracle SQL Developer 1.5

Packt
29 Jan 2010
4 min read
Oracle SQL Developer Tool is a stand alone graphic database developer tool that connects to Oracle as well as third-party databases which can be used to perform a variety of tasks from running simple queries to migration of databases from third party vendor products to Oracle. This article by Dr. Jayaram Krishnaswamy, shows how the reader may use Oracle's most recent tool, the Oracle SQL Developer 1.5 to work with the MySQL database. An example of migrating a table in MySQL to Oracle 10G XE is also described. The Oracle SQL Developer Tool has steadily improved from its beginnings in version 1.1. The earlier versions are briefly explained here. The latest version, SQL Developer 1.5.4 released in March 2009 was described in this article. The SQL Developer tool[(1.5.4.59.40)] bundle can be downloaded from Oracle's web site, Oracle Technology Products. When you unzip the bundle you are ready to start using this tool. You may get an even more recent version of this tool as it is continuously updated. It is assumed that you have a MySQL Server that you can connect to and that you have the required credentials. The MySQL server used in developing this article was installed when the XAMPP bundle was installed. Reader will benefit by reading earlier MySQL articles 1, 2, 3 on the Packt site. Connecting to MySQL Out of the box Oracle SQL Developer 1.5.4 only supports Oracle and MS Access. The product documents clearly says that it can connect to other database products. This article will show how this is achieved. In order to install products from Oracle you must have username and password for the Oracle web Account. Bring up the Oracle SQL Developer application by clicking the executable. The program starts up and after a while the user interface gets displayed as shown. Right click on Connection, the New Connection page opens as shown displaying the default connection to the resident Oracle 10G XE server. Click the menu item Help and choose "Check for Updates". This brings up the wizard displaying the Welcome screen as shown in the next figure. Click Next. The "Source" page of the wizard shows up as shown. The updates for Oracle SQL Developer is already chosen. Place a check mark for "Third Party SQL Developer Extensions". You can choose to install looking for updates on the internet or from the downloaded bundle, if it exists. First try the internet and click Next. This brings up the "Updates" page of the wizard as shown in the next figure. Read the warning on this window. The extensions are not evaluated by Oracle but available. The details of available extensions are as follows: OrindaBuild Java Code Generator version 6.1.20090331 shown in the next figure. The JTDS DBC Driver version 11.1.58.17 shown in the next figure. The MYSQL JDBC driver shown in the next figure: The last one is a patch for the Oracle SQL Developer to fix some of the import, LDAP and performance issues as shown. For this article only the JTDS JDBC driver for MS SQL Server and the MySQL JDBC options were checked. The License agreements are for the JTDS drivers. Click Next. The License agreements must be accepted. Click I Agree. Click Next. This is the download step of the wizard. To proceed further you must have the Oracle Web Account username and password. Here you have the option to signup as well. After a while the new extensions are downloaded as shown in the next figure. Click Finish to close the wizard. You need to restart SQL Developer to complete the installation of the extensions. Click Yes on the "Confirm Exit" window that shows up. Now, when you click New Connection to create a new connection you display the "New / Select Database Connection" as shown. You can now see that other 3rd party databases are added to the window. Choose the tab for MySQL. Fill in the required details as shown in the next figure appropriate for your MySQL installation. You must provide a name for the connection. Herein the connection is named, My_MySQL. The credentials must be provided as shown or that which is appropriate for your installation. The port is the default designated for this server when you install the product. You may accept the other defaults on this page and click Test. The word "success" gets displayed in the status label at bottom left. The connection name and connection details gets added to the page shown above.
Read more
  • 0
  • 0
  • 8687

article-image-enhancing-user-experience-php-5-ecommerce-part-1
Packt
29 Jan 2010
7 min read
Save for later

Enhancing the User Experience with PHP 5 Ecommerce: Part 1

Packt
29 Jan 2010
7 min read
Juniper Theatricals Juniper Theatricals want to have a lot of products on their online store, and as a result they fear that some products may get lost within the website, or not be as obvious to their customers. To help prevent this problem, we will integrate product searching to make products easy to find, and we will add filters to product lists allowing customers to see products that match what they are looking for (for example, ones within their price range). As some products could still be lost, they want to be able to recommend related products to customers when they view particular products. If a customer wants a product, and it happens to be out of stock, then they want to prevent the customer from purchasing it elsewhere; so we will look at stock notifications too. The importance of user experience Our customers' experience on the stores powered by our framework is veryimportant. A good user experience will leave them feeling wanted and valued, whereas a poor user experience will leave them feeling unwanted, unvalued, and may leave a bad taste in their mouths. Search The ability for customers to be able to search, find, and filter products is vital, as if they cannot find what they are looking for they will be frustrated by our site and go somewhere where they can find what they are looking for much more easily. There are two methods that can make it much easier for customers to find what they are looking for: Keyword search: This method allows customers to search the product catalog based on a series of keywords. Filtering: This method allows customers to filter down lists of products based on attributes, refining larger lists of products into ones that better match their requirements. Finding products The simplest way for us to implement a search feature is to search the product name and product description fields. To make the results more relevant, we can place different priorities on where matches were found; for instance, if a word or phrase is found in both the name and description then that would be of the highest importance; next would be products with the word or phrase in the name; and finally, we would have products that just have the word or phrase contained within the product description itself. So, what is involved in adding search features to our framework? We need the following: Search box: We need a search box for our customers to type in words or phrases. Search feature in the controller: We need to add some code to search the products database for matching products. Search results: Finally, we need to display the matching products to the customer. Search box We need a search box where our customers can type in words or phrases to search our stores. This should be a simple POST form pointing to the path products/search with a search field of product_search. The best place for this would be in our website's header, so customers can perform their search from anywhere on the site or store. <div id="search"><form action="products/search" method="post"><label for="product_search">Search for a product</label><input type="text" id="product_search" name="product_search" /><input type="submit" id="search" name="search" value="Search" /></form></div> We now have a search box on the store: Controlling searches with the products controller A simple modification to our products controller will allow customers to search products. We need to make a small change to the constructor, to ensure that it knows when to deal with search requests. Then we need to create a search function to search products, store the results, and display them in a view. Constructor changes A simple switch statement can be used to detect if we are viewing a product, performing a search, or viewing all of the products in the database as a list. $urlBits = $this->registry->getURLBits();if( !isset( $urlBits[1] ) ){$this->listProducts();}else{switch( $urlBits[1] ){case 'view':$this->viewProduct();break;case 'search':$this->searchProducts();break;default:$this->listProducts();break;}} This works by breaking down the URL and, depending on certain aspects of the URL, different methods are called from within the controller. Search function We now need a function to actually search our products database, such as the following: private function searchProducts(){// check to see if the user has actually submitted the search formif( isset( $_POST['product_search'] ) &&$_POST['product_search'] != '' ){ Assuming the customer has actually entered something to search, we need to clean the search phrase, so it is suitable to run in our database query, and then we perform the query. The phrase is checked against the name and description of the product, with the name taking priority within the results. The highlighted code illustrates the query with prioritization. // clean up the search phrase$searchPhrase = $this->registry->getObject('db')->sanitizeData( $_POST['product_search'] );$this->registry->getObject('template')->getPage()->addTag( 'query', $_POST['product_search'] );// perform the search, and cache the results, ready for the// results template$sql = "SELECT v.name, c.path,IF(v.name LIKE '%{$searchPhrase}%', 0, 1) AS priority,IF(v.content LIKE '%{$searchPhrase}%', 0, 1)AS prioritybFROM content c, content_versions v, content_types tWHERE v.ID=c.current_revision AND c.type=t.IDAND t.reference='product' AND c.active=1AND ( v.name LIKE '%{$searchPhrase}%' OR v.contentLIKE '%{$searchPhrase}%' )ORDER BY priority, priorityb ";$cache = $this->registry->getObject('db')->cacheQuery( $sql );if( $this->registry->getObject('db')->numRowsFromCache( $cache ) == 0 ){// no results from the cached query, display the no results// template} If there are some products matching the search, then we display the results to the customer. else{// some results were found, display them on the results page// IMPROVEMENT: paginated results$this->registry->getObject('template')->getPage()->addTag( 'results', array( 'SQL', $cache ) );$this->registry->getObject('template')->buildFromTemplates('header.tpl.php','products-searchresults.tpl.php', 'footer.tpl.php');}}else{// search form not submitted, so just display the search box page$this->registry->getObject('template')->buildFromTemplates('header.tpl.php','products-searchform.tpl.php', 'footer.tpl.php');}} As the results from the query are stored in a cache, we can simply assign this cache to a template tag variable, and the results will be displayed. Of course, as we need to account for the fact that there may be no results, we must check to ensure there are some results, and if there are none, we must display the relevant template. Search results Finally, we need a results page to display these results on. <h2>Products found...</h2><p>The following products were found, matching your search for{query}.</p><ul><!-- START results --><li><a href="products/view/{path}">{ name}</a></li><!-- END results --></ul> Our search results page looks like this: Improving searches We could improve this search function by making it applicable for all types of content managed by the framework. Obviously if we were going to do this, it would need to be taken out of the products controller, perhaps either as a controller itself, or as a core registry function, or as part of the main content/pages controller. The results could either be entirely in a main list, with a note of their type of content, or tabbed, with each type of content being displayed in a different tab. The following diagrams represent these potential Search Results pages.   And, of course, the tab-separated search results.
Read more
  • 0
  • 0
  • 3324
article-image-graphical-user-interfaces-opensips-16
Packt
22 Jan 2010
3 min read
Save for later

Graphical User Interfaces for OpenSIPS 1.6

Packt
22 Jan 2010
3 min read
OpenSIPS Control Panel This tool, also known as opensips-cp, is the new graphical user interface for the SIP proxy. It was designed to be the primary tool to provision parameters for the OpenSIPS modules in the database. The screenshot shows the tools available for OpenSIPS Control Panel. This tool is focused on the provisioning of system parameters. As it is usual for the VoIP providers to develop their own interface with the end users, the tools to manage end users are not available. Developed using PHP, opensips-cp currently features the following modules: CDRviewer dialplan domains dispatcher drouting load balancer Mi Monit nathelper pdt Permissions siptrace smonitor Installation of opensips-cp The step-by-step instructions to install opensips-cp in a server with Debian 5.0 are as follows: Installation instructions change very often. For updates, check the opensips-cp project's website at http://opensipscp.sourceforge.net/. Step 1: Install Apache and PHP as follows: apt-get install apache2 php5 Step 2: Install php5-mysql and php5-xmlrpc packages, and set the right parameters in the php.ini file. (It has been done for you to save time.) apt-get install php5-mysql php5-xmlrpc php-pearvi /etc/php5/apache2/php.ini Please verify that you have set the short_open_tag = On ; option in your php.ini file. Step 3: Download opensips-cp and untar the file. Download opensips-cp from http://opensips-cp.sourceforge.net/index.php?req=download (or copy from DVD) and copy the opensip-cp_3.0.tgz file to /var/www as follows: cd /var/wwwwget http://sourceforge.net/projects/opensips-cp/files/opensipscp/3.0/opensips-cp_3.0.tgz/downloadtar -xzvf opensips-cp_3.0.tgzchown www-data:www-data opensips-cp -R Step 4: Install MDB2. pear install MDB2pear install MDB2#mysqlpear install log Step 5: Configure Apache for OpenSIPS Control Panel. Edit the apache2.conf file. vi /etc/apache2/apache2.conf After doing so, include the following line below the last line: Alias /cp "/var/www/opensips-cp/web" Also, change the owner of the log file: chown www-data:www-data /var/www/opensips-cp/config/access.log Step 6: Install the cdr table schema: cd /var/www/opensips-cp/web/tools/cdrviewermysql -D opensips -p < cdrs.sqlmysql -u root -pmysql> use opensipsmysql -D opensips -p < opensips_cdrs_1_6.mysql Step 7: Edit the cron_job/generate-cdrs.sh file and change the MySQL connection data (hostname, username, password, and database) as follows: cd /var/www/opensips-cp/cron-jobvi generate_cdrs.sh Step 8: Edit the /etc/crontab file and add the following line for a three-minute interval: vi /etc/crontab*/3 * * * * root /var/www/opensips-cp/cron_job/generate-cdrs.sh Step 9: For the smonitor module, you must add two tables to the OpenSIPS database: cd /var/www/opensips-cp/web/tools/smonitormysql -p opensips <tables.sql Step 10: Add a cron job that collects data from the OpenSIPS machine(s). Here is a cron job that collects data at a one-minute interval. (This interval is not arbitrary. It must be set to one minute by design.) vi /etc/crontab* * * * * root php /var/www/opensips-cp/cron_job/get_opensips_stats.php >/dev/null The cron jobs do not need to run as root. You might want to change the user. Step 11: Restart OpenSIPS and Apache.
Read more
  • 0
  • 0
  • 7562

article-image-unittest-python
Packt
21 Jan 2010
11 min read
Save for later

Unittest in Python

Packt
21 Jan 2010
11 min read
So let's get on with it! Basic unittest Before we start talking about new concepts and features, let's take a look at how to use unittest to express the ideas that we've already learned about. That way, we'll have something solid to ground our new understanding into. Time for action – testing PID with unittest We'll visit the PID class (or at least the tests for the PID class). We'll write the tests so that they operate within the unittest framework. We'll be implementing the tests using the unittest framework. Create a new file called test_pid.py in the same directory as pid.py. Notice that this is a .py file: unittest tests are pure python source code, rather than being plain text with source code embedded in it. That means the tests will be less useful from a documentary point of view, but grants other benefits in exchange. Insert the following code into your newly-created test_pid.py (and please note that a few lines are long enough to get wrapped on the article's page): from unittest import TestCase, mainfrom mocker import Mockerimport pidclass test_pid_constructor(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace('time.time') mock_time() mocker.result(1.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) mocker.restore() mocker.verify() self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 0.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 1.0) self.assertAlmostEqual(controller.previous_error, -12.0) self.assertAlmostEqual(controller.integrated_error, 0) def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=1, initial=12, when=43) self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 1.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 43.0) self.assertAlmostEqual(controller.previous_error, -11.0) self.assertAlmostEqual(controller.integrated_error, 0)class test_calculate_response(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace('time.time') mock_time() mocker.result(1.0) mock_time() mocker.result(2.0) mock_time() mocker.result(3.0) mock_time() mocker.result(4.0) mock_time() mocker.result(5.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) self.assertEqual(controller.calculate_response(6), -3) self.assertEqual(controller.calculate_response(3), -4.5) self.assertEqual(controller.calculate_response(-1.5), -0.75) self.assertEqual(controller.calculate_response(‑2.25), ‑1.125) mocker.restore() mocker.verify() def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12, when=1) self.assertEqual(controller.calculate_response(6, 2), -3) self.assertEqual(controller.calculate_response(3, 3), -4.5) self.assertEqual(controller.calculate_response(‑1.5, 4), ‑0.75) self.assertEqual(controller.calculate_response(‑2.25, 5), ‑1.125)if __name__ == '__main__': main() Run the tests by typing: $ python test_pid.py What just happened? Let's go through the code section and see what each part does. After that, we'll talk about what it all means when put together. from unittest import TestCase, mainfrom mocker import Mockerimport pidclass test_pid_constructor(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace('time.time') mock_time() mocker.result(1.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) mocker.restore() mocker.verify() self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 0.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 1.0) self.assertAlmostEqual(controller.previous_error, -12.0) self.assertAlmostEqual(controller.integrated_error, 0) After a little bit of setup code, we have a test that the PID controller works correctly when not given a when parameter. Mocker is used to replace time.time with a mock that always returns a predictable value, and then we use several assertions to confirm that the attributes of the controller have been initialized to the expected values. def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=1, initial=12, when=43) self.assertEqual(controller.gains, (0.5, 0.5, 0.5)) self.assertAlmostEqual(controller.setpoint[0], 1.0) self.assertEqual(len(controller.setpoint), 1) self.assertAlmostEqual(controller.previous_time, 43.0) self.assertAlmostEqual(controller.previous_error, -11.0) self.assertAlmostEqual(controller.integrated_error, 0) This test confirms that the PID constructor works correctly when the when parameter is supplied. Unlike the previous test, there's no need to use Mocker, because the outcome of the test is not supposed to be dependant on anything except the parameter values—the current time is irrelevant. class test_calculate_response(TestCase): def test_without_when(self): mocker = Mocker() mock_time = mocker.replace('time.time') mock_time() mocker.result(1.0) mock_time() mocker.result(2.0) mock_time() mocker.result(3.0) mock_time() mocker.result(4.0) mock_time() mocker.result(5.0) mocker.replay() controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12) self.assertEqual(controller.calculate_response(6), -3) self.assertEqual(controller.calculate_response(3), -4.5) self.assertEqual(controller.calculate_response(-1.5), -0.75) sel+f.assertEqual(controller.calculate_response(‑2.25), ‑1.125) mocker.restore() mocker.verify() The tests in this class describe the intended behavior of the calculate_response method. This first test checks the behavior when the optional when parameter is not supplied, and mocks time.time to make that behavior predictable. def test_with_when(self): controller = pid.PID(P=0.5, I=0.5, D=0.5, setpoint=0, initial=12, when=1) self.assertEqual(controller.calculate_response(6, 2), -3) self.assertEqual(controller.calculate_response(3, 3), -4.5) self.assertEqual(controller.calculate_response(‑1.5, 4), ‑0.75) self.assertEqual(controller.calculate_response(‑2.25, 5), ‑1.125) In this test, the when parameter is supplied, so there is no need to mock time.time. We just have to check that the result is what we expected. The actual tests that we performed are the same ones that were written in the doctest. So far, all that we see is a different way of expressing them. The first thing to notice is that the test file is divided up into classes that inherit from unittest.TestCase, each of which contains one or more test methods. The name of each test method begins with the word test, which is how unittest recognizes that they are tests. Each test method embodies a single test of a single unit. This gives us a convenient way to structure our tests, grouping together related tests into the same class, so that they're easier to find. Putting each test into its own method means that each test executes in an isolated namespace, which makes it somewhat easier to keep unittest‑style tests from interfering with each other, relative to doctest‑style tests. It also means that unittest knows how many unit tests are in your test file, instead of simply knowing how many expressions there are (you may have noticed that doctest counts each >>> line as a separate test). Finally, putting each test in its own method means that each test has a name, which can be a valuable feature. Tests in unittest don't directly care about anything that isn't part of a call to one of the assert methods of TestCase. That means that when we're using Mocker, we don't have to be bothered about the mock objects that get returned from demonstration expressions, unless we want to use them. It also means that we need to remember to write an assert describing every aspect of the test that we want to have checked. We'll go over the various assertion methods of TestCase shortly. Tests aren't of much use, if you can't execute them. For the moment, the way we'll be doing that is by calling unittest.main when our test file is executed as a program by the Python interpreter. That's about the simplest way to run unittest code, but it's cumbersome when you have lots of tests spread across lots of files. if __name__ == '__main__': might look strange to you, but its meaning is fairly straight forward. When Python loads any module, it stores that module's name in a variable called __name__ within the module (unless the module is the one passed to the interpreter on the command line). That module always gets the string '__main__' bound to its __name__ variable. So, if __name__ == '__main__': means—if this module was executed directly from the command line. Assertions Assertions are the mechanism that we use to tell unittest what the important outcomes of the test are. By using appropriate assertions, we can tell unittest exactly what to expect from each test. assertTrue When we call self.assertTrue(expression), we're telling unittest that the expression must be true in order for the test to be a success. This is a very flexible assertion, since you can check for nearly anything by writing the appropriate boolean expression. It's also one of the last assertions you should consider using, because it doesn't tell unittest anything about the kind of comparison you're making, which means that unittest can't tell you as clearly what's gone wrong if the test fails. For an example of this, consider the following test code which contains two tests that are guaranteed to fail: from unittest import TestCase, mainclass two_failing_tests(TestCase): def test_assertTrue(self): self.assertTrue(1 == 1 + 1) def test_assertEqual(self): self.assertEqual(1, 1 + 1)if __name__ == '__main__': main() It might seem like the two tests are interchangeable, since both test the same thing. Certainly they'll both fail (or in the unlikely event that one equals two, they'll both pass), so why prefer one over the other? Take a look at what happens when we run the tests (and also notice that the tests were not executed in the same order as they were written; tests are totally independent of each other, so that's okay, right?): Do you see the difference? The assertTrue test was able to correctly determine that the test should fail, but it didn't know enough to report any useful information about why it failed. The assertEqual test, on the other hand, knew first of all that it was checking that two expressions were equal, and second it knew how to present the results, so that they would be most useful: by evaluating each of the expressions that it was comparing and placing a != symbol between the results. It tells us both what expectation failed, and what the relevant expressions evaluate to. assertFalse The assertFalse method will succeed when the assertTrue method would fail, and vice versa. It has the same limits in terms of producing useful output that assertTrue has, and the same flexibility in terms of being able to test nearly any condition. assertEqual As mentioned in the assertTrue discussion, the assertEqual assertion checks that its two parameters are in fact equal, and reports a failure if they are not, along with the actual values of the parameters. assertNotEqual The assertNotEqual assertion fails whenever the assertEqual assertion would have succeeded, and vice versa. When it reports a failure, its output indicates that the values of the two expressions are equal, and provides you with those values. assertAlmostEqual As we've seen before, comparing floating point numbers can be troublesome. In particular, checking that two floating point numbers are equal is problematic, because things that you might expect to be equal—things that, mathematically, are equal—may still end up differing down among the least significant bits. Floating point numbers only compare equal when every bit is the same. To address that problem, unittest provides assertAlmostEqual, which checks that two floating point values are almost the same; a small amount of difference between them is tolerated. Lets look at this problem in action. If you take the square root of 7, and then square it, the result should be 7. Here's a pair of tests that check that fact: from unittest import TestCase, mainclass floating_point_problems(TestCase): def test_assertEqual(self): self.assertEqual((7.0 ** 0.5) ** 2.0, 7.0) def test_assertAlmostEqual(self): self.assertAlmostEqual((7.0 ** 0.5) ** 2.0, 7.0) if __name__ == '__main__': main() The test_assertEqual method checks that , which is true in reality. In the more specialized number system available to computers, though, taking the square root of 7 and then squaring it doesn't quite get us back to 7, so this test will fail. More on that in a moment. Test test_assertAlmostEqual method checks that , which even the computer will agree is true, so this test should pass. Running those tests produces the following, although the specific number that you get back instead of 7 may vary depending on the details of the computer the tests are being run on: Unfortunately, floating point numbers are not precise, because the majority of numbers on the real number line can not be represented with a finite, non-repeating sequence of digits, much less a mere 64 bits. Consequently, what you get back from evaluating the mathematical expression is not quite 7. It's close enough for government work though—or practically any other sort of work as well—so we don't want our test to quibble over that tiny difference. Because of that, we should use assertAlmostEqual and assertNotAlmostEqual when we're comparing floating point numbers for equality. This problem doesn't generally carry over into other comparison operators. Checking that one floating point number is less than the other, for example, is very unlikely to produce the wrong result due to insignificant errors. It's only in cases of equality that this problem bites us.
Read more
  • 0
  • 0
  • 3050

article-image-managing-discounts-vouchers-and-referrals-php-5-ecommerce
Packt
21 Jan 2010
3 min read
Save for later

Managing Discounts, Vouchers, and Referrals with PHP 5 Ecommerce

Packt
21 Jan 2010
3 min read
Discount codes Discount codes are a great way to both entice new customers into a store, and also to help retain customers with special discounts. The discount code should work by allowing the customer to enter a code, which will then be verified by the store, and then a discount will be applied to the order. The following are discount options we may wish to have available in our store: A fixed amount deducted from the cost of the order A fixed percentage deducted from the cost of the order The shipping cost altered, either to free or to a lower amount Product-based discounts (although we won't cover this one in the article) It may also be useful to take into account the cost of the customer's basket; after all if we have a $5 discount code, we probably wouldn't want that to apply for orders of $5 or lower, and may wish to apply a minimum order amount. Discount codes data When storing discount codes in the framework, we need to store and account for: The voucher code itself, so that we can check that the customer is entering a valid code Whether the voucher code is active, as we may wish to prepare some voucher codes, but not have them usable until a certain time, or we may wish to discontinue a code A minimum value for the customer's basket, either as an incentive for the customer to purchase more or to prevent loss-making situations (for example a $10 discount on a $5 purchase!) The type of discount: Percentage: To indicate that the discount amount is a percentage to be removed from the cost Fixed amount deducted: To indicate that the discount amount is a fixed amount to be removed from the order total Fixed amount set to shipping: To indicate that the discount amount is to be the new value for the shipping cost Discount amount; that is, the amount of discount to be applied The number of vouchers issued, if we wish to limit the number of uses of a particular voucher code An expiry date, so that if we wish to have the voucher code expire, codes with a date after the stored expiry date would no longer work Discount codes database The following table illustrates this information as database fields within a table: The default value for num_vouchers is -1, which we will use for vouchers that are not limited to a set number of issues. Field Type Description ID Integer (Primary Key, Auto increment) For the framework to reference the code Vouchercode Varchar The code the customer enters into the order Active Boolean If the code can be used Min_basket_cost Float The minimum cost of the customer's basket for the code to work for them Discount_operation ENUM('-',%','s') The type of discount Num_vouchers Integer Number of times the voucher can be used Expiry timestamp The date the voucher code expires, and is no longer usable The following code represents this data in our database: CREATE TABLE `discount_codes` (`ID` INT( 11 ) NOT NULL AUTO_INCREMENT ,`vouchercode` VARCHAR( 25 ) NOT NULL ,`active` TINYINT( 1 ) NOT NULL ,`min_basket_cost` FLOAT NOT NULL ,`discount_operation` ENUM( '-', '%', 's' ) NOT NULL ,`discount_amount` FLOAT NOT NULL ,`num_vouchers` INT( 11 ) NOT NULL DEFAULT '-1',`expiry` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,PRIMARY KEY ( `ID` )) ENGINE = INNODB DEFAULT CHARSET = latin1 AUTO_INCREMENT =1;
Read more
  • 0
  • 0
  • 6045
article-image-lesson-solutions-using-moodle-19-part-1
Packt
21 Jan 2010
10 min read
Save for later

Lesson Solutions using Moodle 1.9: Part 1

Packt
21 Jan 2010
10 min read
One of the most challenging aspects of course development often involves simply determining how to select and organize your material. It is very important to be strategic about the type of material you select. Needless to say, every item used in your course should tie directly to course outcomes, and you should make sure that all your items are used in some way. Beyond that, putting the material in your course can feel fairly confusing. Fortunately, Moodle makes it easy to select, incorporate, and organize your content. Moodle also helps you lead students through the material in a way that will maximize the chances of them finishing your course and successfully achieving learning outcomes. Before we go any further, it is worthwhile to take a moment to clarify lessons in Moodle. The terminology can be a bit confusing. In Moodle, a lesson is an activity that fits well within the object-oriented approach of Moodle. It is important to keep in mind that the idea of a lesson in Moodle is fairly limited, and will work within the overall traditional notion of lessons. Selecting and sequencing content for lessons In this section, we'll discuss the best way to select content for your lessons, and how to arrange it so that the students naturally progress to the kinds of competence they need to demonstrate when they get ready for their final assessments. Create conditions for learning Everyone has experienced the pain of a bad lecture when there is just absolutely nothing that reaches out and captures one's imagination. You squirm, you daydream, and then, when it's over, you can't recall a single thing that was said. In that situation, one can safely say that not much learning took place, not just because the delivery might have been ineffectual, but even more compellingly because the speaker failed to ever connect with his/her audience. The educational psychologist Robert Gagne studied the problem of developing ideal learning conditions and, after years of research published his findings in a book titled Conditions of Learning released in 1965. Basically, he discovered that to create ideal learning conditions, there are nine instructional events that must take place. The first event, which he describes as "gaining attention", is critical. If you intellectually stimulate the learners, you're activating receptors in their brain, and they are more likely to pay attention. Once you've gained their attention, you should develop activities that will do the following: Inform learners of objectives and create levels of expectation Stimulate recall of prior learning that relates to your course objectives Present instructional content Guide your students by creating categories and sequences Encourage performance and practice Provide feedback (either automatically or personally) Assess performance Apply knowledge to job or other activity Gagne's "instructional events" are not set in stone, but they are very useful as you put your course together. Notice that they are heavily weighted towards performance, which is not too surprising as Gagne was a resolute behaviorist. Other theorists such as Vygotsky might lean more heavily toward social learning and put more emphasis on the discussion forums. Employ scaffolding Scaffolding is a concept that was developed by Bruner (1975), who used Vygotsky's notions of social and imitative learning in order to explain how people learn from each others in groups and classrooms. Vygotsky held that children learn as they observe teachers and others and, as they adopt practices, they are coached by others to modify their behaviors until they conform to the norm. Bruner took the idea further and proposed that a good way to help students learn is to have a model (a teacher) perform the activity, and then assist the student until he/she is able to perform independently and freely. Bruner thought of the support that is gradually taken away as "scaffolding". If you learned to ride a bicycle as a child, you probably used training wheels, so it might be more comfortable to think of this as a "training wheel" approach. At any rate, wherever and whenever you can, let your students see partially worked problems, and work on the problems with them. Peers can also be training wheels or scaffolding for each other as well, as they provide partial solutions, model essays, and partially-solved problems in anticipation of being able to do things independently. Use chunking to help build concepts Have you ever felt utterly lost in a maze of too much information?, Have you heard anyone remarking that "he/she couldn't see the forest for the trees"? In each case, the problem was that of too many small bits of information and not enough large, organizing sets or categories. To address that problem, educational psychologists have developed a concept they call "chunking", which is basically grouping small items into sets. Essentially, you are mentally recoding low-information content and grouping them together. Ideally, the total number of units will decrease, and what you'll be left with is a small number of high-information "chunks". Chunks are easier to work with than thousands of individual pieces, just as it's easier to pick up a necklace than a thousand individual beads. As you develop your content, think of ways to organize, classify, and categorize to help students access and retrieve information from their working memory. Keep in mind that these are good activities to employ early in the lesson as you seek to help students master the lower-level and foundational cognitive tasks such as identify, define, and describe. Get students involved early Why make students take risks? Why make them introduce themselves, respond to questions, and interact? While it's true that some students will feel a certain amount of discomfort as they make themselves vulnerable, the rewards for the intellectual and emotional risk-taking are very high. They will feel a sense of affiliation, and the essentially dehumanizing e-learning space will become more human, more socially relevant to their lives. Another key consideration is that students are able to practice higher-level cognitive tasks in the discussion board area. They can evaluate, analyze, and synthesize topics on a deeper level through intellectual interaction with peers. Keep it lively Gaining attention is something that you'll need to do throughout the class. Students will constantly need to be stimulated, refreshed, and refocused. Not only will you stimulate the receptors in their brains, you'll also help them formulate their own conversation with the content. As for questions in their minds, be sure to relate the content to something practical and relevant—in the world, in their lives, in their prior knowledge—and then encourage them to discuss and debate. Keeping it lively not only keeps their attention, it also motivates students to return to the course and will help them maintain a high level of enthusiasm. Keep focused There are a number of ways to keep students focused on what you're wanting them to learn. The key is to mix it up, and not repeat the same attention-getting tactics, or you'll risk having students totally tune it out. Try many different strategies—add points, add a video snippet, interject a question, add a graphic or diagram, incorporate a practice quiz or game. Use media strategically Some instructors fall into the trap of media overload. The students may be studying Shakespeare's Hamlet, so they put up links to a hundred different video clips of Shakespearean plays. Yes, one or two are great, after a while, the overload can be distracting. As you select media, put it in a location where the student needs to pause to reflect on content or relate to it in a new way. You can also sequence the media so that it occurs when students may be starting to get bored or losing their focus. Media can help you refocus the students. Diagnostic and developmental/remedial content With Moodle you can design your course so that it builds in material to help students who may need more time, help, and practice on certain aspects of the lessons. For example, you can build in "Test Yourself!" diagnostic quizzes, which can help pinpoint where a student needs to focus more. This sounds a lot like the old pretest and posttest approach, but the difference is that it occurs within your lesson and students can stop along the way to get help. For example, an algebra course could include little "spot check" diagnostic quizzes. They could lead to a review section that is not required for the entire class, but for special needs. It's like having a private tutor. Reward practice The more the students practice, the more likely they are to feel good about their ability to perform, both in real-life applications as well as in their final assignments or tests. So, be sure to provide many opportunities for students to practice, and also for them to receive feedback, either automated or personalized from you or a peer. However, be careful that your quizzes and practice activities are similar in structure, content, and feel to their "high stakes" assignments. If they are not, the students will be discouraged. Also, be sure that the questions and the levels are the same as in the graded assignments. Don't make the final quiz too hard or too easy. Align content, levels of difficulty, time limitations, and testing conditions to those the students will experience later. Build confidence for final graded performance All the content and the activities in your lesson should build toward the students' final performance, whether a final essay, test, or presentation. By the time they reach the end of the lesson, the students should know what to expect and feel comfortable about what lies ahead. Furthermore, they should have a good idea of where to go when they feel lost or have questions. For example, they may be able to refer to a repository of supplemental readings or solved problems, or they can ask questions in the discussion board. At any rate, they always feel as though there is a supportive presence, either in the course itself or in access to the instructor and fellow students. Getting started: A simple example The following screenshot shows a very basic instructional lesson in Moodle. Note that it is essentially a website, and it contains text, links, and an embedded graphic. In fact, it is written in HTML. It is a brief lesson, and so does not have a large number of components. Essentially, the lesson is introducing a concept (the relationship between distance and perspective). It is engaging the student's curiosity by asking a question and then providing an illustrative graphic. The instruction involves testing the student's knowledge by using a "jump question". If you get it right, you proceed to the next item, and if you get it wrong, you're either taken back to the instructional page or jump to a remedial page. However, the jump question could just as easily ask a student what he/she is interested in learning next, or some other exploratory question. When the student clicks on the Continue button at the bottom of the lesson page, he/she is taken to a question page, as shown next: Each answer displays a different feedback. If the student answers correctly, he/she is taken to the next instructional page. An incorrect answer takes the student to a remedial page. This is the normal sequence for a lesson in Moodle. Later, we'll discuss how we can make the best use of the Lesson module.
Read more
  • 0
  • 0
  • 1486

article-image-installation-opensips-16
Packt
21 Jan 2010
4 min read
Save for later

Installation of OpenSIPS 1.6

Packt
21 Jan 2010
4 min read
So, we won't use any shortcuts in the installation. I strongly advise you to install OpenSIPS using Debian. If you choose to install on another platform, you will have to deal with init scripts and fix the installation of the other packages. Hardware requirements There are no minimum hardware requirements for OpenSIPS. It will run on an ordinary PC. The best bets we have are from performance tests realized on the 1.2 version. A PC with the following specifications was capable of 28 million complete calls per hour. The testing server was an ordinary desktop—Intel(R) Core(TM)2 CPU 6300 @ 1.86GHz, 1 GB of memory, and 100 MBps Ethernet card. Unfortunately, there are currently no formulas for OpenSIPS dimensioning. The correct hardware, CPU, and memory shall be obtained empirically. Software requirements The OpenSIPS software runs on a variety of platforms such as Linux, BSD, and Solaris. Some generic packages are available to certain versions of Linux and Solaris. These packages can be downloaded from www.opensips.org/Resources/Downloads. The following packages are required to compile OpenSIPS. gcc (or any other C compiler as suncc or icc) bison or yacc (Berkley yacc) flex GNU make GNU tar GNU install libxml2-dev (if you want to use the presence modules) libxml-rpc (for mi_xmlrpc) Some modules such as MySQL, POSTGRES, RADIUS, and others will require additional packages for compilation. Books from Packt Beginning OpenVPN 2.0.9 Asterisk 1.4 – the Professional’s Guide Cacti 0.8 Network Monitoring FreePBX 2.5 Powerful Telephony Solutions Funambol Mobile Open Source Zabbix 1.8 Network Monitoring [RAW] Asterisk 1.6 Building Enterprise Ready Telephony Systems with sipXecs 4.0   Lab—installing Linux for OpenSIPS All of these labs were prepared using a VMware virtual machine with Debian installed. You may download it from http://cdimage.debian.org/debian-cd/. Warning:The instructions for this lab formats the computer. Back up all the data on your PC before proceeding or follow these instructions in a virtual environment such as VMware or XEN. The steps for installing Linux are as follows: Step 1: Insert the CD and boot the computer using Debian. Press Enter to start the installation. Here, you can also select boot and installation options. Sometimes you may need to choose some hardware-specific parameters for your installation. Press F1 for help, if needed. Step 2:Choose a language of your preference for use in the installation process. Downloading and installing OpenSIPS v1.6. Step 3: Choose the keyboard layout. It is very common to have to choose a keyboard layout, especially in European and Asian countries. Step 4: Choose the Hostname. It is important to choose the name of the server because later you will use this name to access the server. Step 5: Choose the Domain name. The domain name is obvious but important because OpenSIPS use domains to distinguish users, so be sure to enter the domain name correctly. Step 6: Choose a Partitioning method. Linux geeks, certainly, will use the manual option. For the purpose of learning, you can simply use the entire disk. Consult a Linux specialist for the best partitioning scheme for your server. Step 7: Select disk to partition. Now select the disk being used to install Linux. Step 8 : Select All files in one partition (recommended for new users). Again, you can choose how to partition the system. Let's stick with the default installation again. Some advanced users may want to change it. Step 9: Now Finish the partitioning and write changes to disk. Now finish the partitioning step and write changes to the disk. However, never do it if you want to preserve your disk. After the partitioning, all the pre-existing content of the disk will be erased. So think carefully before doing this. I use VMware to test OpenSIPS; it is free and creates a virtual machine where I can work safely Step 10: Write changes to the disk. Here comes the scary part. Confirm that you want to erase all the content of the disk. Well, think twice or even thrice before saying Yes. WARNING:All data on the disk will be destroyed! Step 11: Now Configure time zone. Select the time zone. It is important to have the correct time zone, mainly for reports. If you don't see it correctly, you will end up with voicemail messages having the wrong time. Step 12: Set the Root password to OpenSIPs. Choose a password for your root user. This is the most important password on the system.
Read more
  • 0
  • 0
  • 6150
Modal Close icon
Modal Close icon