《Yii Rapid Application Development Hotshot》

Chapter 1. Develop a Comic Book Database

In this first mission, we will build a personal comic book database with input, update, list, delete, and search capabilities. In the process, we will set up a slick development environment, review Yii basics, and learn some handy tricks and shortcuts.

Mission Briefing

The purpose of this project is to introduce you to Yii and to some great development tools. If you are already familiar with Yii basics, you still might want to check out the tools in this project. NetBeans offers many convenient tools for a PHP developer, such as:

  • Integrated unit testing with PHPUnit
  • Convenient debugging with Xdebug
  • Embedded terminal access

If you are a developer who does not enjoy systems administration on tasks, XAMPP provides a convenient way to get your development stack up and running quickly. By the end of this project, you will have set up your development environment, created, scaffolded, and customized a Yii project, and developed and ran some tests against your code. You will have a web app capable of cataloging your comic book collection, and the home page of the site will look something like this (minus any customizations you choose to add):

Why Is It Awesome?

If you have been a comic book collector for some length of time, your colletion has probably sprawled beyond easy memory access. When you come across an interesting issue, it can be hard to remember—Do I already have this one? A database will help catalogue and organize the items that you have, and it can be extended to keep a list of the items that you want. Yii provides a rapid appliction development framework that enables us to create this functionality in minutes and hours rather than days. This project can be easily adapted to any other type of item that you might collect.

Your Hotshot Objectives

  • setting up the LAMP Stack in One Step with XAMPP
  • Installing NetBeans IDE
  • Adding Xdebug to the Tool Set
  • Unpacking the Yii Framework
  • Initializing the Application Database
  • Generating an Application Scaffold
  • Beginning to Customize the App
  • Geting Familiar with NetBeans and PHPUnit Testing Tools

Mission Checklist

We are going to be setting up our project on 32-bit Ubuntu 12.04. All of these tools are available for Windows and Mac. If you have a Mac, Windows, or a 64-bit system and would like to follow exactly, you could set up a virtual machine with Ubuntu and work from there. Another alternative, especially if you have a background in systems administration, is to set up each individual service in the LAMP stack:

  • Apache
  • MySQL
  • PHP

If you go this route, the instructions will no longer be exact, but they will serve as guidelines and checklists for additional tools you can install.

Setting up the LAMP Stack in One Step with XAMPP

We are going to need a web server, a database, and PHP in order to write this application. LAMP is a term describing a software bundle that includes all of these pieces. XAMPP is one such package. It enables us to install our development tools in one shot. You can achieve the same effect by installing each piece yourself or by using an alternate LAMP package, such as WAMP, for Windows, or MAMP, for Mac OS.

Engage Thrusters

  1. Go to http://www.apachefriends.org/en/xampp.html and find XAMPP for Linux.
  2. Download the latest version of XAMPP and the development package.
  3. Compare the md5 checksums on your system against the md5 checksums on the XAMPP download page to verify the packages by opening a terminal window and entering the following command:
cd ~/Downloads
md5sum xampp-linux-1.7.7.tar.gz
md5sum xampp-linux-devel-1.7.7.tar.gz

After running the preceding command, this is what you will see:

  1. Using full system permissions, unpack the XAMPP package into a public directory.
sudo su
tar xzvf xampp-linux-1.7.7.tar.gzC /opt
  1. Start XAMPP.
/opt/lampp/lampp start

You should see something similar to the following screenshot:

  1. Test your installation by firing up a browser and viewing localhost (http://localhost).

Objective Complete-Mini Debriefing

In one shot, you have installed your LAMP development stack: PHP, MySQL, and Apache, as well as some complimentary tools such as webalizer, phpmyadmin, openssl, and pear. Configuration, data, and logs live under one directory, that is where you installed XAMPP, in our example /opt/lampp.

Classified Intel

Please note that the XAMPP package is recommended for development. If you are deploying your work to a public server, you should research a proper security configuration for your system. We did not do anything with the XAMPP development package, but we will use it later, in the Adding Xdebug to the Tool Set task. One thing you will want to do right away is set up XAMPP to start on reboot. The installation package does not do this for you on Ubuntu. Here is how you do it:

  1. As root, create an init script named lampp in /etc/init.d with the following contents:
#!/bin/bash
/opt/lampp/lampp start
  1. Make the file executable as follows:
sudo chmod +x lampp
  1. Use update-rc.d to install this init script at all run levels.
sudo update-rc.d lamp defaults

Now when you restart your server, XAMPP will start automatically.

Apache User Sharing

  1. If the user www-data does not already exist (check /etc/passwd for an entry for www-data), create it.
sudo adduser --system --group --no-create-home www-data -quiet
  1. Add your user to the www-data group by editing /etc/group and adding yourself to the www-data line. For example, the following line adds the user named lomeara to the www-data group:
www-data:x:33:www-data,lomeara
  1. As root, edit the Apache configuration file /opt/lampp/etc/httpd.conf:
sudo gedit /opt/lampp/etc/httpd.conf
  1. Change the entry for User and Group to www-data.
User www-data
Group www-data
  1. Restart XAMPP.
sudo /opt/lampp/lampp restart
  1. Confirm that XAMPP is running as www-data.
ps aux| grep lampp

Your output should include some lines that look like the following:

www-data  3402  0.0  1.2  50512 12844 ?        S    22:25   0:00 /opt/lampp/bin/httpd -k start -DSSL -DPHP5 -E /opt/lampp/logs/error_log

Installing NetBeans IDE

In the last task, we installed the LAMP stack that will run our app. Now, we will begin to put together our development tool set, starting with an integrated development environment, NetBeans.

Engage Thrusters

  1. Java 7 and JDK 7 are required for the current version of NetBeans (7.1.1). Install them as per your operating system.
sudo apt-get install openjdk-7-jdk openjdk-7-jre
  1. Download the NetBeans installer from netbeans.org. We downloaded the PHP bundle netbeans-7.1.1-ml-php-linux.sh.
  2. If you wish to put NetBeans in a public location, run the installer as root. If you would like to install it for your workspace only, run it as yourself. We are going to install as ourselves.
chmod +x netbeans-7.1.1-ml-php-linux.sh
./netbeans-7.1.1-ml-php-linux.sh
  1. Run NetBeans.
  2. On the NetBeans start page, click on Install Plugins.
  3. Search for Selenium.
  4. Check the box for Selenium Module for PHP in the search results.
  5. Click on Install and follow the installation instructions.
  6. Use the following commands to update Pear. In case you have another instance of PHP/Pear on your system, be sure to work with the one under XAMPP.
sudo /opt/lampp/bin/pear channel-discover pear.phpunit.de
sudo /opt/lampp/bin/pear channel-discover components.ez.no
sudo /opt/lampp/bin/pear channel-discover pear.symfony-project.com
  1. Install PHPUnit.
sudo /opt/lampp/bin/pear install phpunit/PHPUnit
Install Selenium integration.
sudo /opt/lampp/bin/pear install phpunit/PHPUnit_Selenium
  1. Install Story-based test runner for behavior-driven development.
sudo /opt/lampp/bin/pear install phpunit/PHPUnit_Story
  1. Configure NetBeans to use PHPUnit. Open Tools | Options | PHP | Unit Testing and set the correct path: /opt/lampp/bin/phpunit.

Objective Complete-Mini Debriefing

You have installed NetBeans for PHP which will, of course, give you a code editor and project navigation. Some of the things we love include quick access to unit testing, debugging (once we have set up Xdebug), and code coverage. It will also provide remote access to your app once you have deployed it.

Classified Intel

NetBeans provides framework support for Zend, Symfony, and Smarty. It does not currently have support for Yii, but with some configuration tweaks, we will have the benefits of completion and search. Yii provides all the framework tools we will need.

Adding Xdebug to the Tool Set

Continuing to gather and prepare our development tools, we will install Xdebug under XAMPP where it will be accessible from NetBeans.

Engage Thrusters

  1. Unpack the XAMPP development package.
cd ~/Downloads
tar xzvf xampp-linux-devel-1.7.7.tar.gz
  1. Copy the include directory from the package into the root XAMPP directory.
sudo cpr lampp/include /opt/lampp/.
  1. Update the PECL channels database. Remember to work with the instance of PECL under XAMPP if you have more than one instance on your system.
sudo /opt/lampp/bin/pecl update-channels
  1. The autoconf package is a prerequisite for Xdebug. Use the following command to find out if it is installed:
sudo dpkg --list autoconf

If autoconf is installed, the output will look like the following:

||/ Name           Version        Description
+++-==============-==============-============================================
ii  autoconf       2.68-1ubuntu2  automatic configure script builder

If autoconf is not installed, the output will look like the following:

No packages found matching autoconf

Use the following command to install autoconf.

sudo apt-get install autoconf
  1. Install Xdebug with PECL.
sudo /opt/lampp/bin/pecl install Xdebug
  1. The output of the pecl command will confirm the installation of Xdebug in XAMPP extensions. Edit the XAMPP php.ini file.
sudo gedit /opt/lampp/etc/php.ini

Add a line to the end of the file to include the Xdebug extension:

zend_extension = "/opt/lampp/lib/php/extensions/no-debug-non-zts-20090626/xdebug.so"

Also add lines to configure Xdebug:

xdebug.remote_enable = 1
 
xdebug.remote_handler = "dbgp"
xdebug.remote_host = "localhost" xdebug.remote_port = 9000
  1. Restart XAMPP.
  2. Confirm that the extension is activated by visiting the phpinfo() page: http://localhost/xampp/phpinfo.php.

Objective Complete - Mini Debriefing

Now you can set breakpoints in your code to pause execution, step through the lines of code, and examine the values of the variables.

Classified Intel

Once you have hit a breakpoint, you can view the contents of the variables in the toolbars, or when you move the mouse over a variable in the code viewer, the value will appear in the tooltip.

Unpacking the Yii Framework

Once we add one final tool, Yii, we will initialize our project and load it into NetBeans. Adding some Yii-specific configuration to our project in NetBeans will expand the array of tools at hand to include Yii and PHPUnit.

Engage Thrusters

Before we go anywhere, we must grab a copy of Yii and place it where XAMPP can access it.

Installing Yii
  1. Download the latest version of Yii from http://www.yiiframework.com/ (currently 1.1.10).
  2. Unpack the Yii tarball.
cd ~/Downloads
tar xzvf yii-1.1.10.r3566.tar.gz
  1. Move the directory into the XAMPP root.
sudo mv yii-1.1.10.r3566 /opt/lampp/htdocs/.
  1. Create a symbolic link from the version-named Yii directory, yii-1.1.10 in our example, to a directory named yii. (This step is not necessary, but it can be useful when we upgrade. If all outside references use Yii, then we can just change the symbolic link when we upgrade Yii.)
cd /opt/lampp/htdocs/
sudo lns yii-1.1.10.r3566/ yii
  1. Check your Yii installation by visiting http://localhost/yii/requirements/. You may see warnings for Memcache and APC extensions. These extensions are caching utilities for optimizing your site. You can develop without them.
  1. Add XAMPP and Yii framework directories to your executable path. For example, if you are working on a Unix-based system and use bash in your terminal, you can do this by adding the following line to .bashrc in your home directory.
export PATH=${PATH}:/opt/lampp/bin:/opt/lampp/htdocs/yii/framework
  1. Use the source command to evaluate .bashrc in any open terminal windows to pick up the changes.
source ~/.bashrc
Creating a Yii project
  1. Select a directory for your project. We create a directory named projects in our home directory.
cd ~
mkdir projects
cd projects
  1. Run the yiic command to create scaffolding for our project.
yiic webapp cbdb
  1. You will be asked if you want to Create a web application under /home/lomeara/projects/cbdb?, and you will be provided with two options, [yes | no]. Select yes.
  2. Create a link to our new webapp directory in the XAMPP webroot directory.
sudo lns ~/projects/cbdb /opt/lampp/htdocs/.
  1. Change ownership of the directories in your project that are subject to code generation.
cd ~/projects/cbdb/protected
sudo chgrp www-data models controllers views
  1. Open http://localhost/cbdb/ in your web browser to view your newly created project.
Adding project in NetBeans
  1. In a terminal window, determine the version of PHP that you are running under XAMPP.
/opt/lampp/bin/php -v

You will see output that looks like the following:

PHP 5.3.8 (cli) (built: Sep 19 2011 13:29:27)
Copyright (c) 1997-2011 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies
    with Xdebug v2.2.0rc1, Copyright (c) 2002-2012, by Derick Rethans
  1. Open NetBeans and click on File | New Project:
  1. Select PHP Application with Existing Source and click on Next.
  1. Browse to your project directory (For example, /home/lomeara/projects/cbdb).
  2. Select the correct version of PHP from step 1 (for us, the version is 5.3) and click on Next.
  1. Accept the defaults on the next screen and click on Finish. You should now see cbdb in the project window.
  1. Right-click on the project name and select Run to launch the webapp in a browser.
Configuring the project in NetBeans
  1. Click on File | Project Properties.
  2. In the Sources category, select the test folder (/home/lomeara/projects/cbdb/protected/tests).
  3. In the PHPUnit category, activate Use Bootstrap, and select the Bootstrap file (/home/lomeara/projects/cbdb/protected/tests/bootstrap.php). Then activate Use XML Configuration and select the XML configuration file (/home/lomeara/projects/cbdb/protected/tests/phpunit.xml).
  4. In the PHP Include Path category, add the Yii Framework root (/opt/lampp/htdocs/yii) and PHPUnit (/opt/lampp/lib/php/PHPUnit).
  5. Open Tools | Options | Miscellaneous | Files and in the field Files Ignored by the IDE add yiilite\.php| in front of CVS. The result will look something like the following screenshot:
  1. Open Tools | Options | PHP | Debugging and uncheck Stop at First Line.
  2. Restart NetBeans.

Objective Complete - Mini Debriefing

We have created our first project and added it to NetBeans. We have updated the NetBeans project to utilize PHPUnit. There are just a few more useful tools to put at our fingertips as we move forward.

Initializing the Application Database

We are going to set up a database connection in NetBeans and load in a basic schema to get you started.

Prepare for Lift Off

We have put together some tables to capture basic comic book information:

  • book
  • author
  • illustrator
  • type (serial, trade, graphic novel)
  • grade (mint, near mint, fair, poor, and so on)

Yii requires consistency in table naming: singular or plural, but not both. Singular is recommended for simplicity.

Engage Thrusters

  1. In NetBeans, go to Windows | Services.
  2. Right-click on Databases and select New Connection….
  3. You should see a MySQL driver. Click on Next.
  4. Accept the connection defaults. (Click on the Test Connection button to verify it works).
  5. Click on Finish.
  6. Right-click on MySQL Server and select Create Database….
  7. In the New Database Name: field, enter cbdb.
  8. Check Grant Full Access To: and select *@localhost.
  9. Click on Ok.
  10. Right-click on jdbc:mysql://localhost:3306/cbdb and select Execute Command.
  11. Paste the contents of schema.sql into the editor window (labeled SQL Command 1).


Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

  1. Click on the Run SQL button (or Ctrl + Shift + E) to create the tables.

This entity relationship diagram illustrates the relations between the tables:

Objective Complete - Mini Debriefing

Now that the schema has been loaded, we can use the IDE to inspect the tables and contents. To do so, click on cbdb in the Services window to expand it and see the table fields. As you can see, a book record includes an ID, title, type, publication date, value, price, grade, notes, and flags for signed and bagged. This table contains no data, so let's look at a table that does have information in it. Right-click on grade and select View Data. A SQL command window will open with the query in it. Below that, you should see the output of the query, the data that is in the grade table.

NetBeans provides a nice interface for interacting with a MySQL database. As we have demonstrated, you can access and inspect the database as well as build queries and execute commands. This is useful when you are working with one database and even better when you are working with more than one.

Generating an Application Scaffold

Yii provides some great web-based scaffolding tools. Now that we have a schema in place, we can use those tools to provide basic access to our comic book objects.

Prepare for Lift Off

First, we have to update our application configuration to point to our database. Then we will enable Gii, Yii's graphical code generator. With Gii, we will generate scaffolding for each entity in our database. At the end, we will have a very basic, but functional, comic book database webapp.

Engage Thrusters

  1. Fire up NetBeans and go to the Projects window.
  2. Expand cbdb | Source Files | protected | config.
Updating Database Configuration
  1. Open main.php.
  2. Scroll down to the db section under components. You will see an active entry for the default sqlite database.
  3. Let's start by commenting out that entry to disable it.
/*
    'db'=>array(
        'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
    ),
*/
  1. Now uncomment the example MySQL entry below that and input our database information. Change the dbname to cbdb. Everything else should be the same, unless you created a user and/or set a password for your database.
'db'=>array(
    'connectionString' => 'mysql:host=localhost;dbname=cbdb',
    'emulatePrepare' => true,
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
)
Enabling Gii
  1. We are going to enable Gii so that we can scaffold the objects that are in our database. Scroll up to the modules section of the config file (around line 23).
  2. Uncomment the gii section and give the password attribute a value.
'modules'=>array(
    'gii'=>array(
    'class'=>'system.gii.GiiModule',
    'password'=>'yiibook',
    // If removed, Gii defaults to localhost only. Edit //carefully to taste.
    'ipFilters'=>array('127.0.0.1','::1'),
)
  1. Right-click on the project and select Run to go to the webapp in a browser, then add ?r=gii to the URL. The whole URL should be http://localhost/cbdb/index.php?r=gii. Hit Enter to load Gii.
  2. Enter the password that you specified in the config file.
  3. Select Model Generator to get started; we are going to generate models for all of the tables in the database.
  4. We will start with a table that does not have dependencies—type. Enter type in the Table Name field. You will see that the field Model Class is filled in for you as you type. The screen should look like this:
  1. Click on the Preview button to review the code that will be generated. Then click on Generate.
  2. Repeat steps 6 and 7 for each table in the following order: grade, book, publisher, bookpublisher (change the suggested model name to BookPublisher), person, bookauthor (change the suggested model name to BookAuthor), bookillustrator (change the suggested model name to BookIllustrator), tag, and booktag (change the suggested model to name BookTag).
  3. Now we will create views and controllers for all of the models we just created. Click on Crud Generator in the Generators menu.
  1. Enter Type in the Model Class field. Now you will see the Controller ID field auto-completed for you.
  1. Click on Preview and you will see a list of many files: one controller and several view items.
  1. Click on Generate to create the files. The output will include a link to try it now. You can click on this to open a new window and test out the CRUD functionality you just created for the Type object.
  2. Repeat steps 10, 11, and 12 for each model: Grade, Book, Publisher, Person, Tag. We are not going to generate CRUD for our join tables.

Objective Complete - Mini Debriefing

Great; we have a functioning web app now. Sure, it is not ready for prime time. We are going to want to spend some time making the interface user-friendly and connecting the objects. But it's not a bad start.

If you go back to the main screen, you will not see any links to get you to the objects we just added. For the moment, you can get to them by manipulating the URL. To get to the books, change your URL to http://localhost/cbdb/index.php?r=book.

From this page, you can click on Create Book to add a book to our database (if you are asked to log in, use admin/admin). This interface leaves something to be desired. For one, we will have to input raw index and Boolean values in Type, Signed, Grade, and Bagged. If you input something like this, you can add an entry.

In the next section, we will connect these pieces to make the user experience much smoother.

Classified Intel

At this point, you can deactivate Gii. You get the picture about how powerful it is. You do not want to accidentally leave it activated when you deploy to a public server. So go back into the configuration file and comment out the Gii section. We can always uncomment it in the future if we need it again.

Beginning to Customize the App

Now we have a functional, but not very accessible site. We are going to start customizing the framework that Yii provides. This is where the real development work begins. In this project, we will concentrate on making what is available more accessible. You may want to frequently go back to the site in your web browser and reload to view the effects of these steps.

Engage Thrusters

Let's start by updating the menus so that we can click to our comic book information.

Menus
  1. In NetBeans, expand Source Files | protected | views | layouts and open main.php.
  2. This file is the main wrapper for your site. It contains the header and footer that are on every webpage.
  3. For now, our site is for personal use, so we will leave the login and comment out About and Contact lines 32 and 33.
'items'=>array(
    array('label'=>'Home','url'=>array('/site/index')),
    //array('label'=>'About', 'url'=>array('/site/page', 'view'=>'about')),
    //array('label'=>'Contact', 'url'=>array('/site/contact')),
    array('label'=>'Login', 'url'=>array('/site/login')),
),
  1. In the line above Login (34), add new lines for the objects that we want to manage through the interface.
array('label'=>'Comic Books','url'=>array('/book')),
  1. It would be nice to access the other items in the same way, but we don't want to fill up the screen with objects. Let's add the other objects to a drop-down list, under Comic Books, by creating a sublist containing a link to Publishers.
array(
    'label'=>'Comic Books', 
    'url'=>array('/book'),
    'items' => array(
        array('label'=>'Publishers', 'url'=>array('/publisher')),
    )
),
  1. Now we will change the CSS for the site to display the drop-down menu. Open Source Files | css | main.css and replace the mainmenu section (around line 50) which looks like this:
#mainmenu
{
    background:white url(bg.gif) repeat-x left top;
}
 
#mainmenu ul
{
    padding:6px 20px 5px 20px;
    margin:0px;
}
 
#mainmenu ul li
{
    display: inline;
}
 
#mainmenu ul li a
{
    color:#ffffff;
    background-color:transparent;
    font-size:12px;
    font-weight:bold;
    text-decoration:none;
    padding:5px 8px;
}
 
#mainmenu ul li a:hover, #mainmenu ul li.active a
{
    color: #6399cd;
    background-color:#EFF4FA;
    text-decoration:none;
}

Replace the previous code with the following:

#mainmenu
{
    background:white url(bg.gif) repeat-x left top;
}
 
#mainmenu ul
{
    padding:6px 20px 5px 20px;
    list-style: none; 
     margin: 0; 
    padding: 0; 
    position: relative; 
    height: 30px;
}
 
#mainmenu ul li
{
    display: block; 
    height: 28px; 
    float: left; 
    overflow: visible;
    position: relative;
 
}
 
#mainmenu li ul
{
    position: absolute;
    top: 24px;
    left: 10px;
}
 
#mainmenu li ul li 
{
    display: none;
}
 
#mainmenu ul li a
{
    float: left; 
    display: block; 
    color:#ffffff;
    background-color:transparent;
    font-size:12px;
    font-weight:bold;
    text-decoration:none;
    padding:5px 8px;
}
 
#mainmenu .active a, #mainmenu li:hover > a, 
#mainmenu li:hover > ul li
{
    display: block;
    color: #6399cd;
    background-color:#EFF4FA;
    text-decoration:none;
}
  1. If we are going to support login, we should move our protected menu item inside of the login. We could do this with the "visible" flag, but that will complicate things for our drop-down visibility. We chose to split the menu into a Logged In Version and a Not Logged In Version. Here is the result in Source Files | protected | views | layouts | main.php:
<div id="mainmenu">
<?php 
  if (Yii::app()->user->isGuest) {
    $this->widget('zii.widgets.CMenu',array(
      'activeCssClass' => 'active',
      'activateParents' => true,
      'items'=>array(
        array('label'=>'Home', 'url'=>array('/site/index')),
      //array('label'=>'About', 'url'=>array('/site/page', 'view'=>'about')),
      //array('label'=>'Contact', 'url'=>array('/site/contact')),
      array('label'=>'Login', 'url'=>array('/site/login')),
      ),
    )); 
  } else {
    $this->widget('zii.widgets.CMenu',array(
       'activeCssClass' => 'active',
       'activateParents' => true,
       'items'=>array(
         array('label'=>'Home', 'url'=>array('/site/index')),
         array('label'=>'Comic Books', 
           'url'=>array('/book'),
          'items' => array(
            array('label'=>'Publishers', 'url'=>array('/publisher')),
          )
        ),
        array('label'=>'Logout ('.Yii::app()->user->name.')', 'url'=>array('/site/logout'))
      ),
    ));                     
  }
?>
</div><!-- mainmenu -->
Forms

Let's make that comic book create form better. We will start with some quick-to-implement customizations. The first will be to fix the drop-down menus for Type and Grade.

  1. Start by extending the Type model. Open Source Files | protected | models | Type.php and add a function that returns all of the Type values in a list format.
public function getTypeOptions()
{
    return CHtml::listData(Type::model()->findAll(),'id','name');
}
  1. Then, change the book form (which conveniently happens to be the same file for create and update). Open Source Files | protected | views | book | _form.php. We will replace the section for Type which looks like the following:
<div class="row">
    <?php echo $form->labelEx($model,'type_id'); ?>
    <?php echo $form->textField($model,'type_id',array('size'=>10,'maxlength'=>10)); ?>
    <?php echo $form->error($model,'type_id'); ?>
</div>

The previous section should be changed from a text field to a dropdown, using our new model function, as follows:

<div class="row">
    <?php echo $form->labelEx($model,'type_id'); ?>
    <?php echo $form->dropDownList($model, 'type_id', Type::model()->getTypeOptions()); ?>
    <?php echo $form->error($model,'type_id'); ?>
</div>
  1. Follow that format to make the Grade field a drop-down list too.
  2. Similarly, let us change the input for the Boolean values Signed and Bagged by changing the text field to a checkbox. For example, we changed Bagged as follows:
<?php echo $form->checkbox($model, 'bagged'); ?>

After these changes, the create comic book form will look like the following screenshot:

  1. We can make the publication date look very nice with the Yii Jui widget. Start by replacing the publication_date text field in the form with the following:
<?php $this->widget('zii.widgets.jui.CJuiDatePicker', array(
    'name' => 'publication_date',
    'attribute' => 'publication_date',
    'model'=>$model,
    'options'=> array(
      'dateFormat' =>'yy-mm-dd',
      'altFormat' =>'yy-mm-dd',
      'changeMonth' => true,
      'changeYear' => true,
      'appendText' => 'yyyy-mm-dd',
    ),
  )); 
?>

Objective Complete - Mini Debriefing

At this point, your site will include a custom menu that lets you click to access the comic book and publisher objects. It will also have a better, custom comic book create/update form with drop-down menus for Type and Grade and a date picker for Publication Date.

Classified Intel

You may have noticed that your URL contains a reference to the index.php file. You can configure Yii and Apache to provide cleaner, more readable URLs with the following changes:

  1. In NetBeans, expand the Source Files | protected | config and open main.php to edit.
  2. Change the name of the app from My Web Application to Comic Book DB.
 'name'=>'Comic Book DB'
  1. Scroll down to components and uncomment the urlManager section.
  2. Create a .htaccess file in the root directory of the project. (Right-click on Source Files | New | Other. Then select Other | Empty File. Give it the name .htaccess and click on Finish.)
RewriteEngine on
 
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
 
# otherwise forward it to index.php
RewriteRule . index.php
  1. Access http://localhost/cbdb/book in your web browser. You should see the book's index page.

Getting Familiar with NetBeans and PHPUnit Testing Tools

We advocate for Test Driven Design, but we are not going to review it in depth. Hopefully, you are already familiar with this methodology and aware of the enormous benefits it can impart to development. We are going to assume that you already know about test-driven design or will learn about it and bring it into your software development practice. In this task, we are just going to show you some tools you can use in its application.

Engage Thrusters

  1. Currently, we have no tests set up, but we can get the hang of testing by right-clicking on the project root (cbdb) and selecting Test.
  2. The tests (at this point, there are zero tests) will run and display results in the bottom pane—not very exciting. Let's make some tests. NetBeans will tell PHPUnit to generate tests for you. Expand Source Files | protected | models, right-click on Type, and select Tools | Create PHPUnit tests.
  1. PHPUnit will create a file named TypeTest.php with tests for all of the functions in the Type model. Let's add an actual test for the getTypeOptions function we wrote earlier.
  2. First, we need to create a test database. Go to the services window, right-click on your MySQL connection, and select Create Database.
  3. Name the database cbdb_test and set Grant Full Access To to *@localhost.
  4. Set up the tables by right-clicking on Execute Command for cbdb_test then inputting and running the exact same schema definition we used to create our development database.
  5. Now we can configure the test database connection. Uncomment and complete the database section in Source Files | protected | config | test.php.
'db'=>array(
    'connectionString' => 'mysql:host=localhost;dbname=cbdb_test',
    'emulatePrepare' => true,
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
),
  1. Next, we will add a test for the getTypeOptions function we wrote earlier. In TypeTest.php, scroll down to testGetTypeOptions (around line 100) and replace:
// Remove the following lines when you implement //this test
$this->markTestIncomplete(
    'This test has not been implemented yet.'
);

With the following:

$options = Type::model()->getTypeOptions();
$this->assertTrue(is_array($options));
$this->assertEquals(3, count($options));
  1. Let's prepare to run the test again, but this time collect code coverage information. First, we are going to tell PHPUnit that we only care about coverage for certain directories. Edit Test Files | phpunit.xml and add the following section:
<filter>
    <whitelist>
        <directory suffix=".php">../models</directory>
    </whitelist>
</filter>
  1. Right-click on the project root (cbdb). Select Code Coverage | Collect and Display Code Coverage as shown in the following screenshot:
  1. Run the tests again like we did in step 1, then get the code coverage report by right-clicking on the project root (cbdb) and selecting Code Coverage | Show Report.

Objective Complete - Mini Debriefing

There is so much more you can do with testing. We will revisit testing and introduce more tools and techniques in future chapters, but we encourage you to hone your testing and continue to explore the tools.

Classified Intel

When you generate the test coverage, PHPUnit marks the test stubs with "to-do" comments. To get the list of reminders of items you intended to complete, open the tasks list Window | Tasks (in other versions it may appear as Window | Action Items). It will provide you with a list of all errors and warnings in your code, as well as all to-do items.

Mission Accomplished

You have now successfully configured your development environment, generated and customized a Yii app, and begun to write your unit tests. This is a great baseline that you have created to work on the remaining projects in the book.

You Ready to go Gung HO? A Hotshot Challenge

Here are a few suggestions to go gung ho at this point:

  • Customize the look of your site:
    • Change up the CSS.
    • Customize the landing page.
  • Write a greeting for visitors.
  • Write yourself a nice welcome for when you log in.
  • Add validation to your forms.
    • What happens if you input a null value for Publication Date?
    • How is the security? Can you input illegal SQL in your text fields?
  • Create your own user and deactivate the default accounts: demo and admin.
  • Explore the tools that NetBeans provides. Could you have completed all of the steps of the project from within NetBeans? What hot keys do you find save the most time?
评论 X

      友荐云推荐
      Copyright 2011-2014. YiiBook.com