You are on page 1of 28

The Yii Framework Larry Ullman

This is a copy of the Larry Ullman series Learning the Yii Framework. See http://www.larryullman.com/2009/06/18/introduction-to-the-yii-framework/. 1. Introduction to the Yii Framework In 2009, I had three decent-size Web sites to develop, so I thought I might try using a PHP framework for the first time, instead of coding everything from scratch. Ive used Ruby on Rails for Web development before, so Im comfortable with frameworks and the MVC architecture, but I wanted to educate myself on PHP frameworks. After researching a handful of frameworks, and after an unsatisfying attempt to use Zend Framework, I finally settled on, and really came to appreciate the Yii Framework. At the time, the Yii Framework was still quite new, and there are still bugs to be worked out (for the more advanced stuff), but Yii works so well that its very easy to use. In this first of several posts on the Yii Framework, I just discuss setting up and testing Yii. (Note: In October 2010, Ive updated this entire series to reflect changes in Yii since this series was written, and to take into account feedback provided through the comments. Some outdated material will be crossed out, but left in to reflect how things have changed since the series was begun in June 2009.) The first thing you need in order to use the Yii Framework is access to a Web server with PHP installed, of course. But if youre reading this, Im going to assume you have access to a PHP-enabled server. Note that the Yii Framework does require PHP 5.1 or above. Fortunately, the framework will test your setup for you! Start by downloading the latest stable version of the Yii Framework. At the time of this writing, thats 1.0.6 1.1.4. The file you download will be named something like yii-version.release.ext and is only around 2MB. Expand the downloaded file to create a folder of stuff:

CHANGELOG, LICENSE, README, and UPGRADE text documents demos folder framework folder requirements folder

You should read the README and LICENSE docs, of course, but the folders are most important here. The demos folder contains four Web applications written using Yii: a blog, the game Hangman, a basic Hello, World!, and a phone book. The demos are great for seeing working code as youre trying to write your own. The framework folder is whats required by any Web site using Yii. The requirements folder is something simple and brilliant I also assume that you already know what the Web root directory is on your computer or server: this is the folder where your URL points to. In other words, when you go to http://localhost or http://www.example.com in your Web browser, it grabs documents out of the Web root folder. Going with Yiis conventions, Ill call this WebRoot. Create a new folder in your WebRoot called yii, and copy the framework and requirements folders there. Then go to yourURL/yii/requirements in your Web browser (for example, http://localhost/yii/requirements). You should see a report as to whether or not your setup meets the minimum requirements.

Assuming your setup passed all the requirements, youre good to go on. Note that you dont necessarily need every extension: you just really need the Yii Framework requirements, PDO, and the PDO extension for the database youll be using. (If youre not familiar with it, PDO is a database abstraction layer, making your Web sites database-agnostic.) In my next post, Ill show you how to use the command-line Yii tools to create your first Web application. Its pretty sweet stuff and is the closest thing to Ruby on Rails that Ive seen (which I consider to be a very good thing). Subsequent posts will walk you through developing a Yii-based application. Use the series links at the top and bottom of this post to navigate the series. You may also want to read my posts on the MVC architecture.

2. Getting Started with the Yii Framework Many, many moons ago I wrote a post introducing the Yii framework. Its a framework for creating Web applications using PHP 5 (or greater) that Ive really liked since I originally started with it. Ruby on Rails was the first Web development framework I personally used (back in 2005) and Zend was the first PHP framework. I love the former, and Yii is quite like it in many ways, but I never really took to Zend. In that first post, I discussed just downloading and testing Yii; here Ill walk through creating the beginnings of a Web application. (Note: In October 2010, Ive updated this entire series to reflect changes in Yii since this series was written, and to take into account feedback provided through the comments. Some outdated material will be crossed out, but left in to reflect how things have changed since the series was begun in June 2009.) For the specific example, Ill use an employees-departments Web application, with a list of departments and a list of employees, each employee being in only one department. This is a classic go-to example, as its easy to understand, practical, uses more than one database table, and is extensible in many ways. To start, though, youll use the command-line Yii tools to create the applications frame. If youll be putting the site on a server that you do not have command-line access to, then you should install a complete Web server (Apache, PHP, MySQL, etc.) on your computer, run through these steps, then upload the finished project once youve completed it. If you dont already have a Web server on your computer, Id recommend using XAMPP (for Windows) or MAMP (for Mac), both of which are free and extremely easy to use. The first thing youll need to do is make sure you have the latest version of the Yii framework. My first post discusses how to get it. Then youll want to put the framework folder in a logical location on the server. You dont need to put it within the Web directory (arguably, you shouldnt) but nearby, like in the directory below makes the most sense. For example, on my setup, the htdocs folder is the Web root, which is to say that http://www.example.com points there.

My directory structure. Tip: If youre going to be using Yii for multiple sites on the same server, place the framework folder in a logical directory relative to every site. That way, when you update the framework, youll only need to replace the files in one place. Next, youll need to get yourself into a command-line environment, like a DOS window/console on Windows or the Terminal application on Mac OS X (and some versions of Linux). Then move yourself into the framework directory. On my server, this means executing this line: cd /Users/larryullman/Sites/YiiBlogSite/framework Youll need to change the particulars to match your setup. The next step is to tell the yiic application, found in the framework folder, to create a new site. The syntax is

yiic webapp path/to/directory But before you even begin to use this command, let me explain it a bit, as its very important and can be complicated. The yiic file is an executable that runs using the computers command-line PHP and that really just invokes the yiic.php script. You may be able to call it using just yiic or using ./yiic (i.e., run the yiic command found in the current directory). Or you can more explicitly call either script using php yiic or php yiic.php. Or you may need to indicate the PHP executable to be used: C:\php\php.exe yiic. You should try the variations on this command, as applicable to your computer, just to make sure you can invoke yiic, prior to trying to create the Web application. Besides properly executing the yiic script, another gotcha can arise if you have more than one version of PHP installed on your computer. To confirm the version being used, run php -v (again, you may need to provide the full path to the PHP executable). On Mac OS X and Unix, you can use which php to reveal the PHP executable being used by the command php. These steps can help solve confusing problems. For example, on my Mac, I use MAMP Pro for PHP and MySQL Web development, but when I execute PHP through the command-line, Ill actually be invoking the PHP installed with the operating system. This can be a problem, as the different versions of PHP may or may not meet the Yii requirements outlined in my first post. I know when I first tried this, the command-line PHP (installed with the OS) did not support the required PDO extension, even though the Web version of PHP (in MAMP Pro) did. My solution was to explicitly name my MAMP PHP executable when running yiic: /Applications/MAMP/bin/php5.3/bin/php yiic. Once you know youve figured out the proper syntax for invoking yiic, you follow that by webapp, which is the command for create a new Web application. Follow this with the path to the Web application itself. Given the directory structure already indicated (in the above figure), the command would be just ./yiic webapp ../htdocs Or php yiic webapp ../htdocs Or whatever variation on that you need to use. Youll be prompted to confirm that you want create a Web application in the given directory. Enter Y (or Yes) and press Return. After lots of lines of responses, you should see a message saying that the application has successfully been created. To confirm this, load the site in your browser (by going through a URL, of course):

The Auto-Generated, Basic Yii Application As for functionality, the generated application already includes: a home page with further instructions a contact form, complete with CAPTCHA a login form

the ability to greet a logged-in user by name logout functionality

Its a very nice start to an application, especially considering you havent written a line of code yet. Do note that the contact form will only work once youve edited the configuration to provide your email address. For the login, you can use either (username/password): demo/demo or admin/admin. Lastly, the exact look of the application may differ from one version of the Yii framework to another. In terms of files on the server, within the application directory (htdocs, for me), youll find: assets css images index-test.php index.php protected themes The assets folder will be used by the Yii framework primarily for jQuery (the JavaScript framework) integration. The css and images folders are obvious. The entire site will also be run through one of the two index files (more on this in the next post). The protected folder is actually the most important one: youll edit code found in that folder to change the look and behavior of the site. And themes allows you to create variations on the sites template, just like themes in a WordPress blog. Tip: The assets folder must be writable by the Web server or else odd errors will occur. This shouldnt be a problem unless you transfer a Yii site from one server to another and the permissions arent correct after the move. So thats the start of a Yii-based Web application. For every site you create using Yii, youll likely go through these steps. In the next post, Ill start demonstrating how you can configure the application, and alter it for an employees-departments example.

3. Configuring Yii This is the third post in my series on Yii, my favorite PHP framework. In the first, I show how to download and test the framework itself. In the second, I show how to create a basic Web application. The end of that post also discusses the files and folders in the application directory. Youll want to be familiar with those as you go forward. In this post, I discuss how youll want to configure your Yii-based application, including handling errors, adding components, and establishing a database connection. This post does assume you have an existing application to work with; if you dont, follow the steps in the previous two posts. (Note: In October 2010, Ive updated this entire series to reflect changes in Yii since this series was written, and to take into account feedback provided through the comments. Some outdated material will be crossed out, but left in to reflect how things have changed since the series was begun in June 2009.) There are a couple of ways you can configure how your Yii application behaves. For the most part, youll do this through the protected/config/main.php file, but first I want to talk about the index.php file, created in the root of your Web application directory. This is a bootstrap file, meaning that all user interactions actually go through it. For example, showing an employee record might be through the URL www.example.com/index.php/employee/show/id/34 and updating a department record might involve submitting a form to www.example.com/index.php/department/update/id/3. Both URLs request just that one PHP script. The index.php file is generated when you use the command-line yiic script. Theres only seven lines of noncommented code in it. The first identifies the location of the Yii framework: $yii=dirname(__FILE__).'/../framework/yii.php'; The path indicated should already be correct (because its created when the framework is used to make the application), but you can change this value if you move the framework or the index file. The second line identifies where the configuration file is: $config=dirname(__FILE__).'/protected/config/main.php'; The default behavior is to put the protected directory, where all the application files reside, in the same directory as the index file. My inclination is to move it outside of the Web directory, like so:

Modified Yii Layout In such a case, I edit my index.php file to read: $config= '../protected/config/main.php';

Note that its perfectly reasonable to move the location of your application files (i.e., the protected folder), but you should not change the names or structure of the folders found within the protected directory. Tip: Moving the protected folder outside of the Web root directory is just an extra security precaution. Its not required, and you may not want to bother with the change, especially as youre just getting started. The next line of code turns on debugging mode: defined('YII_DEBUG') or define('YII_DEBUG',true); Youll want debugging enabled when developing a site, but disabled once live. To disable debuggin, remove or comment out that line. I normally just comment it out, so that I can re-enabled debugging later. Or you can change it to something like this, so that you can add debugging to a page on the fly: if (isset($_GET['debug'])) define('YII_DEBUG', true); If you do that, then to debug any page on the fly, change the URL from, for example,www.example.com/index.php/site/contact to www.example.com/index.php/site/contact/debug/true. The next line of code dictates how many levels of call stack are shown in a message log: defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3); The call stack is a history of what files, functions, etc., are included, invoked, and so forth. With a framework, the simple loading of the home page could easily involve a dozen actions. In order to limit the logged (i.e., recorded) data to the most recent, useful information, the call stack is limited by that line to just the most recent three actions. The last two lines of the bootstrap file include the framework and start the application. Dont mess with these! require_once($yii); Yii::createWebApplication($config)->run(); And thats really all there is to do in the index.php page. As of Yii 1.1., the framework creates another bootstrap file: index-test.php. It is exactly the same as index.php, except that index-test.php includes a different configuration file: /protected/config/test.php instead of /protected/config/main.php. However, the test configuration file just includes the main configuration file, then also enables the CDbFixtureManager component, which is used for unit testing. The index-test.php file also omits the call stack limitation. Most of the configuration occurs in the main.php configuration file, found within the protected/config directory (see the above image). Theres also a console.php config file, but thats for a command-line version of the application. I wont discuss that here, but you would edit it if you have command-line scripts associated with your application. The configuration file returns a multi-dimensional array of information, some of which is pre-defined. You do want to make sure that the proper syntax is maintained as you edit this, so be careful in matching parentheses and using commas where necessary. For starters, youll want to change the name of the application, which is used in the default HTML design, in page titles, and so forth:

'name'=>'Wicked Cool Yii Site', Next, under the modules section of the returned array, you should enable Gii. Gii is a Web-based tool that youll use to generate Models, Views, and Controllers for the application. To enable Gii, just remove the comment tags/* and */that surround this code: 'gii'=>array( 'class'=>'system.gii.GiiModule', 'password'=>'SECURE', ), Also enter a secure password in the code, one that only you will know. Tip: Gii was added to Yii in version 1.1.2, and it replaces functionality available using the command-line Yii tools. Moving down the file, in the components section of the returned array, youll probably want to enable urlManager. Just remove the comment code that surround the following: 'urlManager'=>array( 'urlFormat'=>'path', 'rules'=>array( '<controller:w+>/<id:d+>'=>'<controller>/view', '<controller:w+>/<action:w+>/<id:d+>'=>'<controller>/<action>', '<controller:w+>/<action:w+>'=>'<controller>/<action>', ), ), This component changes URLs to be more search engine and user-friendly. For example, the default URL for a page could be something like www.example.com/index.php?r=site/contact, but urlManager will turn that into www.example.com/index.php/site/contact. If you want to take this further, its possible to configure urlManager, along with an Apache .htaccess file, so that index.php no longer needs to be part of the URL. Next, youll almost always want to establish the database connection (unless youre not using a database, of course). To do so, return an array that includes a connection string, a username, and a password. By default, a connection string is predefined for the SQLite database: 'db'=>array( 'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db', ), If youre using SQLLite, just change the code so that it points to the location of your SQLLite database. If youre not using SQLLite, comment out or remove those three lines of code. If youre using MySQL, the proper code looks like: 'db'=>array( 'connectionString' => 'mysql:host=localhost;dbname=testdrive', 'emulatePrepare' => true, 'username' => 'username', 'password' => 'password',

'charset' => 'utf8', ), The connection string is a DSN (Database Source Name), which has a precise format. It starts with a keyword indicating the database application being used, like mysql, pgsql (PostgreSQL), mssql (Microsofts SQL Server), or oci (Oracle). This keyword is followed by a colon, then, depending upon the database application being used, and the server environment, any number of parameters, each separated by a semicolon:

mysql:host=localhost;dbname=test

mysql:port=8889;dbname=somedb

mysql:unix_socket=/<em>path</em>/<em>to</em>/mysql.sock;dbname=whatever Indicating the database to be used is most important. For me, when using MAMP on Mac OS X, I had to set the port number as it was not the expected default (of 3306). On Mac OS X Server, I had to specify the socket, as the expected default was not being used there. Also do keep in mind that youll need to have the proper PHP extensions installed for the corresponding database, like PDO and PDO MySQL. You should obviously change the username and password values to the proper values for your database. You may or may not want to change the character set. Within the log component section, I enable CWebLogRoute. This is a wonderfully useful debugging tool that adds tons of details to each rendered page. Heres the code for the config file: 'log'=>array( 'class'=>'CLogRouter', 'routes'=>array( array( 'class'=>'CFileLogRoute', 'levels'=>'error, warning', ), array ( 'class' => 'CWebLogRoute' ) ), ), And heres an example output:

Web Log Output

Finally, towards the end of the default configuration file youll find the adminEmail parameter. Change this to your email address, so that you receive error messages, contact form submissions, whatever: 'params'=>array( 'adminEmail'=>'whatever@example.edu', ), As you can tell, editing and adding components is where a lot of the configuration takes place. The ones Ive highlighted are just the most immediately important, in my opinion, but there are certainly others, involving caching, security, themes, and more. One cool feature of Yii is that not all named components will be loaded for every request. Some, like the logging components are, but others are only loaded when required, thereby minimizing the performance impact of using many components. One more configuration parameter that used to be in the default configuration file but now needs to be added is an indicator of the default controller. In other words, if no controller is specified in the URL, what controller will be called? Without further configuration, the site controller will be the default. To change that to a different controller, add: 'defaultController' => 'login', Note that this particular line will not work out of the box as only the site controller exists. But you would make this change if you had created a protected/controllers/LoginController.php file (or if any controller file exists for whatever you make be the default). Also note that you add this line so that its a top-level array element being returned (i.e., it does not go within any other section; its easiest to add it between the basePath and name elements, for clarity). And thats a quick intro to configuring your Yii application. As always, thanks for reading and let me know if you have any questions or comments. In my next post, Ill discuss a database design Ill use in subsequent posts. After that, Ill show you the magic: auto-generated Models, Views, and Controllers using Yiis tools.

4. Defining Databases for the Yii Application This is the fourth post in my series on Yii, my favorite PHP framework. In the first, I show how to download and test the framework itself. In the second, I show how to create a basic Web application. In the third, I walk through some configuration options. In this post, I want to discuss the database design that will be the foundation for the Yii application Im demonstrating (in the subsequent four posts). The specific example will be a classic employees-departments application, with each employee in one department. This post does assume you have an existing Yii application to work with, most likely by following the steps in my previous posts. (Note: In October 2010, Ive updated this entire series to reflect changes in Yii since this series was written, and to take into account feedback provided through the comments. Some outdated material will be crossed out, but left in to reflect how things have changed since the series was begun in June 2009.) The goal here is to create a Web application that allows you to add, edit, display, and delete the departments and employees of a hypothetical corporation. These four features are known as CRUD: Create (i.e., INSERT), Retrieve (i.e., SELECT), Update, and Delete. These four acts are the cornerstone of every content management system, and just about any other data store as well. To pull it off, youll need to create a series of files for both employees and departments:

A Model file, which defines the thing itself A Controller file, which defines the actions that can be taken with the thing Several View files, which act as the user interface, including forms for adding new items and updating existing ones

With some frameworks, doing all of this requires quite a bit of busywork: selecting a template, copying, pasting, editing, creating new files, etc., etc. With Yii, and with other frameworks like Ruby on Rails, the majority of the work will be done for you by doing the proper preparation and then invoking the built-in tools. To start, then, I need to think about the Models, which will be represented by database tables in this example. The two tables will be rather simple, with a one-to-many relationship between them: there will be many employees in each department but each employee will only be in one department. You can put whatever you want in your employees table, but for the purposes of this Learning the Yii Framework series, itll be defined with this SQL command CREATE TABLE Employee ( id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, departmentId TINYINT UNSIGNED NOT NULL COMMENT "CONSTRAINT FOREIGN KEY (departmentId) REFERENCES Department(id)", firstName VARCHAR(20) NOT NULL, lastName VARCHAR(40) NOT NULL, email VARCHAR(60) NOT NULL, ext SMALLINT UNSIGNED NULL, hireDate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, leaveDate DATETIME NULL, INDEX name (lastName, firstName), INDEX (departmentId) )

In a post on MVC, I discuss conventions and how its best to just go along with the frameworks rules. For example, I normally use all lowercase and underscores for my column names (e.g., first_name) but I am using camelcase here to be in keeping with Yii and the general OOP standards (when the values are retrieved for an individual employee, specific columns will be referenced using, for example, $model->firstName). The same goes for the primary key column, which should just have the name id. The departmentId column will be a foreign key to the departments table, to reflect which department the employee is in. Ill address the added comment shortly. The ext column is intended to represent the employees phone extension (mostly I put it in there to demonstrate numeric constraints in the Model). The hireDate is populated when a row is inserted (if no date is provided for it). Do note that Im assuming MySQL here, and how timestamps behave does change from version to version. And theres an index on the persons name for sorting purposes, plus one on the departmentId column as itll be used in joins. The departments table only contains three two columns. The first is the primary key; second is the name of the department (a unique index is placed on it), and the second is the department head. That value will be the ID value from the employees table for the associated head. An index is placed on the deptHeadId column, as itll be used in joins. (And, this means theres also a one-to-one relationship between the two tables.) (Note: I dropped a third column from the original version of this series as it was confusing to many people.) CREATE TABLE Department ( id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, name VARCHAR(40), UNIQUE (name) ) Now, as for the comments in the Employee tableYii will recognize FOREIGN KEY constraints that exist and use that information to help define the Model. But since MySQL doesnt always enforce foreign key constraints (depending upon the version of MySQL and the storage engine being used), you can fake the constraint for Yiis sake by adding a comment like the one associated with the Employee.departmentId column. That comment suggests that the the departmentId column is a foreign key that references the id column in the Department Model. If you dont add this comment, its not a big deal as you can write the code to indicate the relation yourself, but its nice that Yii will do it for you. Okay, thats it! Once youve created the two tables, you can return to the Yii tools to create the Models, Controllers, and Views (as Ill do in the next post). Before you do so, you should revisit your database tables to make sure they are exactly how you want them to be. Since Yii will auto-generate a bunch of code for you, any changes you make after Yii writes this code means youll need to go in and manually edit that much more code. So get it right now, as much as you can!

5. Creating Models, Views and Controllers in Yii This is the fifth post in my series on Yii, my favorite PHP framework. In the first, I show how to download and test the framework itself. In the second, I show how to create a basic Web application. In the third, I walk through some configuration options. In the fourth, I explain the database design to be used by the sample application that this and the subsequent posts discuss. In this post, I show how to use Yiis Gii tool to create Models, Views, and Controllers in your Yii application. This post does assume you have an existing application to work with, most likely by following the steps in my previous posts. (Note: In October 2010, Ive updated this entire series to reflect changes in Yii since this series was written, and to take into account feedback provided through the comments. Some outdated material will be crossed out, but left in to reflect how things have changed since the series was begun in June 2009. This post had the heaviest revisions, as the command-line tools were replaced by the Web-based Gii.) Yii, like Ruby on Rails and a few other frameworks, has tools that will generate code, files, and directories for you. As you can imagine, this is a tremendous time saver. Yii originally offered just the command-line yiic tool for this purpose (also used to create the Web application itself). As of Yii 1.1.2, theres now the Webbased Gii, which runs in the browser. In this post, Ill explain how to use Gii to create the fundamental Model, View, and Controller files required by the application (subsequent posts cover how to edit the autogenerated code to suit your needs). Note: You can still use the command-line yiic, if you prefer that environment. This post demonstrates Gii using an employees-departments example, with the two database tables already created (see the previous post). A couple notes up front:

Because Gii does so much of the work for you, you really want to have your design as complete as possible. If done properly, after creating your database tables following these next steps, you wont use Gii again for the project. You must enable Gii, using the instructions in the third post. Because Gii is a powerful tool, its best not to enable it on a live server. Ideally youll enable Gii on a development server, use it, and disable it, and then later put the site online. If youll be putting the completed application on a live server which you dont have command-line access to, you can develop the whole thing on your local computer, then upload the generated and edited files. Again, the command-line tool is really for the initial setup. The successful use of the command-line tool relies upon having a properly configured command-line version of PHP installed and used to execute the command-line script. See my notes in the second post for more. Make sure that the two database tables exist. Make sure that youve edited your main.php configuration file so that the Yii application can connect to the database. See the third post for more.

Tip: For extra security, Gii can be set to only work for a specific IP address (i.e., yours). Assuming you understand all of the above and have taken the requisite steps, you should now load Gii in your browser. Assuming your site is to be found at www.example.com/index.php, the Gii tool is at www.example.com/index.php/gii/. This assumes youre using the URL management component in Yii. If not, head to www.example.com/index.php?r=gii. You should be taken to the login screen, where you just enter the Gii password (established in the configuration file), and click Enter. Assuming you entered the correct password, youll see a splash page and a list of options (as links).

Gii Splash Page The first thing youll want to do is generate the Models. Click the Model Generator link. On the following page: 1. Enter Employee as the Table Name. 2. Enter Employee as the Model Class. Youll notice that the form automatically copies the table name as the Model name. 3. Click Preview. Youll see a table appear at the bottom of the form, indicating the files to be generated (just one in this case). 4. Click Generate. Tip: To automatically model every database table, just enter * for the table name.

Generating a Model You should then see a message indicating that the code was created (you can check for the new file to confirm this). If you see an error about an inability to write the file, youll need to modify the permissions on the protected/models directory to allow the Web server to write there. Once this works for you, repeat the process for the Department table. These steps generate the protected/models/Department.php and protected/models/Employee.php scripts, which you can now open and check out in your text editor or IDE. When using Yii version 1.0.10 1.1.4, the Model file had about 60 110 lines of code. Ill get into the specific code in a subsequent post, but youll see methods that define validation rules for the Model, relations this Model has to others, and so forth.

Next, and this is big, create CRUD functionality. CRUD stands for Create, Retrieve, Update, and Delete. In other words, everything youd do with database content. Click the Crud Generator link. On the following page: 1. Enter Employee as the Model Class. 2. Enter employee as the Controller ID. Youll notice that the form automatically copies the Model Class, in lower camelcase as the controller ID. So Employee becomes employee, SomeThing would become someThing. 3. Click Preview. Youll see a table appear at the bottom of the form, indicating the files to be generated. 4. Click Generate. Tip: If you know you wont need certain functionality, such as the ability to create or delete a Model type, deselect the corresponding checkboxes. You should then see a message indicating that the code was created. Again, if you see an error about an inability to write the file, youll need to modify the permissions on the protected/controllers and protected/views directories to allow the Web server to write there. Once this works for you, repeat the process for the Department Model. The resulting page will also offer up a link to go test the generated files.

Crud Generator That one step will create the Controller file for each Model (DepartmentController.php and EmployeeController.php), plus a View directory for each, with eight View files per Model: _form.php _search.php _view.php admin.php create.php index.php update.php view.php The form file is used to both create and update records. The search script is a custom search form. The _view.php file is a template for showing an individual record. The admin script creates a tabular listing of the

Model, with links to CRUD functionality. The index script is really intended for a public listing of the records. The view script is used to show the specifics of an individual record. And the create and update files are wrappers to the form page, with appropriate headings and such.

Edit for Yii 1.0: In earlier versions of Yii, prior to 1.1, the view.php file was called show.php and index.php was called list.php. There were also fewer View files created.

Note: You will have situations where youd have a Model for something but not want CRUD functionality, so dont assume you always take both steps. So thats it! You can click logout, then click webapp to return to the home page. You can confirm that what you did worked by checking out the new directories and files or by going to a URL. Depending upon whether or not you added urlManager to the applications configuration, the URL would be something like www.example.com/index.php/employee/ or www.example.com/index.php?r=employee. You will see that there are no employees or departments to list and also that you cant add any new records without logging in (the default is admin/admin). In my next post, Ill discuss how to start editing the generated code to make the application behave more like you want it to in the real world. But thanks to Yiis Gii tool, about 80% of the work has been done for you!

6. Basic Model Edits in Yii This is the sixth post in my series on Yii, my favorite PHP framework. In the first, I show how to download and test the framework itself. In the second, I show how to create a basic Web application. In the third, I walk through some configuration options. In the fourth, I explain my database design, and how you should define it with Yii in mind. In the fifth, I show how to use Yiis Gii tool to create Models, Views, and Controllers in your Yii application. In this post, I walk through some of the basic edits youll likely make to a Model after its been created by Yiis Gii tool. In doing so, youll also get a general introduction to the Yii Model as a whole. For some of the code, Ill be using the employees-departments example Ive been developing throughout these posts. You may want to reread earlier posts to get a handle on those. (Note: In October 2010, Ive updated this entire series to reflect changes in Yii since this series was written, and to take into account feedback provided through the comments. Some outdated material will be crossed out, but left in to reflect how things have changed since the series was begun in June 2009.) The Model represents the data used by an application. Normally the data comes from a database, but it could also be from a form submission (to be emailed, not stored, like the ContactForm Model in the base Yii application). In Yii, a Model based upon a database table is defined as a class that extends (i.e., inherits from) Active Record. Active Record is a common and popular design, also used by the Ruby on Rails framework. This means that most of the Models functionality isnt defined in your Model, but rather in the parent Active Record class. So when looking at your Model code, dont be surprised that you wont find methods for creating and updating records (i.e., saving the Model) or whatever, and thats all inherited. Since that functionality is defined already for you, the goal of your Model should be to extend and tweak that functionality as needed. Within a Model, there are certain Yii-specific methods (class functions) that youll commonly use. Some of these will be created when you use Yiis Gii tool to generate the Model, others can be added whenever. I want to focus on those Yii-specific methods here, as theyll be common to most Models. (In later posts, Ill write up examples of custom methods that might be added to Models.) One of the most important methods is rules(), which lists the rules by which the Model data must abide. Much of your applications security and reliability stems from this method. In fact, this one method represents one of the key benefits of using a framework: data validation. Whether a new record is being created or an existing one is updated, you wont have to write, replicate, and test the data validation routines: Yii will do them for you. As a comment in the Model indicates, you only establish rules for fields (i.e., Model attributes) whose data may be provided by users. You wouldnt, for example, declare a rule for the Employee id field, which is the MySQL-generated primary key. The rules() method, like most of the Yii methods, returns an array of data: public function rules() { return array(/* actual rules */); } For the actual rules, the Yii documentation covers them in full (see this and this), but Ill highlight the main ones. As youll see, each rule is written so that it returns an array. The first, most obvious, restriction is to indicate that a field is required. Just use a comma-separated string of field names as the first returned value and the word required as the second:

array('name, email, subject, body', 'required'), You can also specify that a value must be a number or, more specifically, an integer. This syntax is slightly different. Here, I indicate that the ext field must be an integer: array('ext', 'numerical', 'integerOnly'=>true), For strings, you can restrict the length to a maximum value: array('name','length','max'=>40), Or a minimum value: array('name','length','min'=>6), Or both: array('name','length','min'=>6, 'max'=>40), Another useful validation routine is to check that a string is an email address. I do that here, to a userEmail field: array('userEmail', 'email'), To indicate that a string needs to be a URL, use: array('link', 'url'), Another useful rule is for comparisons, like when a user registers and you have to make sure that the confirmed password matches the password: array('password1', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'), There is also the safe rule. This rule is used to provide access to data that isnt otherwise validated. For example, an email address is already considered to be safe because it must abide by the email rule, but the Employee Model has the leaveDate field which wont have any rules applied to it (in part, because there are no date-specific rules and also because the field can be null). To be able to refer to that value, it must be declared as safe: array('leaveDate', 'safe'), If there are multiple fields to make safe, just separate them with commas. Theres also a rule to indicate which fields should be safe to search on. By default, every rule is made safe in a search, but you may want to change that behavior by removing fields from the list: array('id, departmentId, firstName, lastName, email, ext, hireDate, leaveDate', 'safe', 'on'=>'search'), So, using this information, the complete rules() method for my Employee Model is: public function rules() {

return array( array('departmentId, firstName, lastName, email, hireDate', 'required'), array('departmentId, ext', 'numerical', 'integerOnly'=>true), array('firstName', 'length', 'max'=>20), array('lastName', 'length', 'max'=>40), array('email', 'length', 'max'=>60), array('email', 'email'), array('leaveDate', 'safe'), array('id, departmentId, firstName, lastName, email, ext, hireDate, leaveDate', 'safe', 'on'=>'search'), ); } Moving on, another key Model method is relations(), which indicates the relationship between Models. If your database is designed properly, this method will already be properly filled out, again thanks to Gii. Heres how the relations() method in the Employee Model looks: public function relations() { return array('department' => array(self::BELONGS_TO, 'Department', 'departmentId') ); } The relation is given a name, here department. The relation indicates that the departmentId column in the Employee Model (i.e., this one) belongs to the Department Model. Heres how this will come into play: When loading the information for an employee, you can also load any of its relations. By doing so, references to department will equate to the Department Model record that is the employees department. So if the $model object represents the Employee being viewed, then $model->department->name would be the name of the department that the employee is associated with. In the Department Model, this relation is defined: public function relations() { return array('employees' => array(self::HAS_MANY, 'Employee', 'departmentId') ); } So if $model represents a specific Department being viewed, then $model->employees is an array of Employee objects, each of which representing one Employee in that department. The relations between Models is a key player in complex MVC sites. Through properly defined relations, associated content can be retrieved. Youll learn more about this in the next couple of posts. Moving on, a more trivial, but still nice, method is attributeLabels(). This method returns an associative array of fields and the labels to use for those fields in forms, error messages, and so forth. The Yii framework does a great job of making these conversations automatically, like firstName becoming First Name and departmentId becoming just Department. But you may want to still customize these. For the Employee Model, heres what I have: public function attributeLabels() { return array( 'id' => 'Employee ID',

'departmentId' => 'Department', 'firstName' => 'First Name', 'lastName' => 'Last Name', 'email' => 'Email', 'ext' => 'Ext', 'hireDate' => 'Hire Date', 'leaveDate' => 'Leave Date', ); } So theres a little bit of customizing youll want to do to your Models to start off. As I said, youll also add your own methods later on. And theres some other Yii-specific methods that I do use often, like beforeSave(), which is code to be run before a Model is saved, and beforeValidate(), which is executed before validation takes place. This last method is useful if theres some data manipulation you want to do behind the scenes before the Model is run through all the validation requirements. And theres the search() method, which Ill have to address in a separate post. But, the absolute most important Model functions are rules() and relations().

7. Basic View Edits in Yii This is the seventh post in my series on Yii, my favorite PHP framework. In this post, I walk through some basic View edits youll make to the code auto-generated by the Yii framework. For some of the code, Ill be using the employees-departments example Ive been developing throughout these posts. You may want to reread earlier posts to get a handle on those. (Note: In October 2010, Ive updated this entire series to reflect changes in Yii since this series was written, and to take into account feedback provided through the comments. Some outdated material will be crossed out, but left in to reflect how things have changed since the series was begun in June 2009.) When you use the command-line and Gii tools to create a new Web application, the Yii framework generates a series of files and folders for you, from configuration files to controllers to Views. The Views are a series of PHP scripts, organized by folder. The first one youll want to edit is protected/views/layouts/main.php (where protected is the root application directory). This is the template for every page within the application. Youll likely want to change most of the file to create your own look, but I want to highlight a few key points. To start in the HEAD, youll see that external files are linked using <link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/main.css" /> Whenever you see Yii::app(), that refers to the Web application as a whole. You can access information about the user viewing a page, about the current or previously-viewed page, etc., there. Yii::app()->request specifically references the current page being accessed (or requested). The ->baseUrl part refers to the root URL for the application, like http://www.example.com. You should use Yii::app()->request->baseUrl for references to external filesCSS, JavaScript, images, and so forthas the relative path to them can become muddled with the changed Yii URLs (like www.example.com/index.php/site/login). Next, youll see the pages title set dynamically: <title><?php echo CHtml::encode($this->pageTitle); ?></title> By default, the pageTitle value will be the applications name (defined in the config file) plus something about the current page. Later on, Ill show you how to change this. The CHtml::encode() method is just used to protect against Cross-Site Scripting (XSS) attacks. Youll see it used liberally (and appropriately) in the View files. Youll also see in the main layout file: <div id="logo"><?php echo CHtml::encode(Yii::app()->name); ?></div> Yii::app()->name is the name of the Web application, as established in the config/main.php file. You may or may not want to use it in your Views, but thats where the value comes from. Next up, the default layout uses a widget: <?php $this->widget('zii.widgets.CMenu',array(...

Widgets are a way to include a nugget of PHP code in a View using an external file. Theyre best for things that arent tied to specific Views and that you may want to drop in anywhere. Plus it allows you to further separate out chunks of code for easier management and portability. The above code says that the CMenu widget should be dropped in here. That widget is part of the Zii extension (to the Yii framework). For more on widgets, see the Yii documentation.

Edit for Yii 1.1: Yii 1.1 took a bunch of the best extensions and placed them in their own namespace, zii. Whereas earlier versions of Yii created a MainMenu component, Yii 1.1 uses the CMenu widget. The default layout also makes use of the CBreadcrumbs widget, include in the Zii extensions.

Finally, the layout script has this line, which is the most important: <?php echo $content; ?> Now you wont find a reference to the $content variable anywhere in your code and do note that its just $content, not $this->content or $model->content. This is where the page-specific content gets inserted into the layout. All the other HTML and PHP is the template for the entire site; the value of $content is what makes pageX different from pageY. So where does it come from? Tip: The exact structure of the URLs will depend upon whether youve enabled urlManager or not and, if so, how its configured. See the post on configuring Yii for more. If youre viewing a page like www.example.com/index.php/employee/view/id/1, which is intended to show the employee with an ID of 1, the actionView() method of the EmployeeController class is called. That method loads the Employee Model with a primary key of 1, then renders the view View, passing along the Model in the process. That code is (this is from protected/controllers/EmployeeController.php): public function actionView($id) { $this->render('view',array( 'model'=>$this->loadModel($id), )); } The loadModel() method of this Controller class does the actual Model retrieval, and I wont worry about that right now, but the $this->render() part says to render the View to be named, in this case, view. That means that Yii will execute the PHP script protected/views/employee/view.php. That script uses a $model variable (passed in the above code) to display information about the employee within some context (specifically, view.php script uses zii.widgits.CDetailView to list the details) . The result of this executed View script is, behind the scenes, assigned to $content, and therefore dropped into the appropriate place in the layout. Thats how the system works. One last thing about the layout scripts is that you can easily have different layouts for different sections of the application. To do so, in the Controller method, change the layout value before rendering the view. Provide the name of the layout file, minus the extension. So this line says to use protected/views/layouts/home.php for the index action: class SiteController extends CController {...

public function actionIndex() {... $this->layout = 'home'; In fact, as of Y 1.1.?, the framework creates both one column and two column layouts, each of which use the main.php template file. The Controller then indicates which layout to use for the entire Controller: class EmployeeController extends Controller { public $layout='//layouts/column2'; Note: $this->layout within a class method is equivalent to just public $layout outside of any method (as in the above code). The first example changes the layout for a specific action; the second for the Controller as a whole. Moving on to the View scripts, one of the first things I normally do is change the basic formatting to whatever youre looking for. For example, the default appearance of a show View is a table of information about the Model: labels and values. Normally you dont want to show all of the Model data, and youll display it in DIVs or paragraphs. These are simple edits. As the above code shows, the Model information will be passed under the name model, so you can use $model->whatever to access the values of the different fields.

Edits for Yii 1.1: There are a number of View file changes, although none that are dramatic: What was previously the list (list.php) View file is now index (index.php). The index page makes use of a CListView widget to list the records. The admin page makes use of a CGridView widget to display all the records. The show file (show.php) is now called view (view.php). It makes use of the CDetailView widget to show the information for a specific record. Multiple View files can make use of the _view.php script, which is a template for showing an individual record. Every view file identifies breadcrumb information at the top, which will tie into the CBreadcrumbs widget referenced in the main layout file.

Tip: If you log into the site (using admin/admin if you havent changed the login system) and then go to www.example.com/index.php/department/, you can already create a few department records to make better sense of what I write below. The index and admin Views both show multiple Model records, using Zii widgets. index.php uses the CListView widget, using the _view.php script as the template. If you edit either _view.php or how CListView is configured (in index.php), youll change the listings. The admin page, accessed by clicking on Manage XXX, uses the CGridView widget. This widget creates a table of data, with links to view, edit, or delete specific records. The table can be paginated and searched, using Ajax. Its really sharp and a great demonstration of how much Yii will do for you. This figure shows the departments listing, without having made any changes to what Yii created:

Department Admin Page

The create and update Views have some page header stuff, then include the form View, using this code: <?php echo $this->renderPartial('_form', array('model'=>$model)); ?> That code renders a partial View in that place, passing along the Model information to _form.php. Looking at the generated code, the Department form is fine, as it just provides an input for the departments name. For the Employee Model, however, theres some customization youll need to do there. You can check it out by heading to www.example.com/index.php/employee/create/. By default, the forms generated by Gii includes elements for every Model attribute, save for the primary key. But some fields, like the dates created or modified, may be automatically populated with timestamps, and therefore arent inputted by the users. And, with related Models, like Employee and Department, youll end up needing a drop-down menu in the one to select a value from the other, like choosing what department an employee is in. The Yii-generated code wont do this for you; the form will just have a text field created by this code: <?php echo $form->textField($model,'departmentId'); ?> The $form variable is an object of CActiveForm type. The textField() method creates a text input. The first argument says that the input should be for the $model object (which is the current Model instance, coming from the Controller). The second argument identifies the property in the Model that this element is for. To create a drop-down associated with another Model, youd replace that code with: <?php echo $form->dropDownList($model,'departmentId', CHtml::listData(Department::model()->findAll(), 'id', 'name')); ?> First, the dropDownList() method of the $form object creates a drop-down list. You need to tie it to the form-associated Model, so the first argument is just $model, the same variable passed to this View when its rendered. The second argument is the name of the form field/Model field: here, the departmentId field in the Employee Model. Next, you need to provide the method with the list of values to use for the drop-down menu, which is achieved by calling CHtml::listData(). That method returns a list of values that are usable in drop down menus. Its data source should be the list of Departments. To retrieve those, use Yiis approach for retrieving all the records in a Model: ModelName::model()->findAll(). So to fetch every department, use Department::model()->findAll(). The final two arguments (to the CHtml::listData() method) are the fields to use for the drop-down menus value and displayed text. Those should be id (the departments ID) and name. Another thing youll want to do in all your View files is remove or edit the links to the different admin features. Finally, you may decide you want to change the pages title. To do that, use code like: <?php $this->pageTitle = $model->something; ?> Note that youre assigning a value to $this->pageTitle here, not $model->pageTitle, but youll likely use the contents of $model, like a title or name field, as the page title value. You can also still add in the application name, if you want, by concatenating in Yii::app()->name.

Whew! So thats my whirlwind tour of basic View edits youll want to make to a fresh Yii application. In my next post, Ill discuss basic Controller edits, of which there are surprisingly few, I find. As always, thanks for reading what I have to say and do let me know if you have any questions or comments.

8. Basic Controller Edits in Yii After using Yiis command-line and Gii tools to build an applications base structure, and then to create its Models and crud functionality, theres still quite a bit of customizing to do (although Yii really does perform the bulk of the work). Previous posts discuss some of the common changes one makes to Models and Views at this point in the development stage; here Ill discuss Controllers. I have personally found that I dont make nearly the level of alterations to my auto-generated Controllers as I do to my Models and Views. This makes sense, as the Model should have the bulk of the code, the View is the interface the end user sees, and the Controller is largely an agent between the two (see my series on the MVC architecture for more on this). (Note: In October 2010, Ive updated this entire series to reflect changes in Yii since this series was written, and to take into account feedback provided through the comments. Some outdated material will be crossed out, but left in to reflect how things have changed since the series was begun in June 2009.) Edit for Yii 1.1: The $defaultAction line is no longer present. Also, the names of some of two of the action methods have changed to match the new names of the corresponding View files: actionView() and actionIndex().

The Controller represents the actions a user takes with a site: views a specific record, updates a record, lists all the records, etc. A user request (i.e., the loading of a URL) is handled by the Yii application, then passed off to the corresponding Controller. Its the Controllers duty to perform any necessary work, likely involving the loading or manipulation of some Models, then pass data off to the View. As with any class definition, all of the tasks are performed within methods. The first thing youll encounter within a Controller class is a variable called $layout: public $layout='//layouts/column2'; As explained in the post on Views, this variable dictates which of the two built-in layoutsone column or two columnthe Controller uses. You can change this value to change the layout for the entire Controller, or you can change $this->layout within any of the methods. Another class variable, which used to be written into the class but now has to be added is: public $defaultAction='admin'; As just stated, Controllers are the actions one takes, listing information, showing particular records, handling form submissions, and so forth. For each action there is a corresponding method in the Controller class: actionIndex(), actionView(), actionCreate(), etc. The above line dictates which method is called if not otherwise specified. So with that line, the URL www.example.com/index.php/employee calls the actionAdmin() method whereas www.example.com/index.php/employee/create calls actionCreate(). The default value, if you dont use that line, is to call actionIndex(). Your Controllers should also have several non-action methods, including accessRules(). This method is a key part of the security picture, dictating who can do what. For the what options, you have your actions: list, show, create, update, and delete. Your who depends upon the situation, but to start theres at least logged-in and not logged-in users, represented by * (anyone) and @ (logged-in users), accordingly. Depending upon the login system in place, you may also have levels of users, like admins. So the

accessRules() method uses all this information and returns an array of values. The values are also arrays, indicating permissions (allow or deny), actions, and users: public function accessRules() { return array( array('allow', // allow all users to perform 'index' and 'view' actions 'actions'=>array('index','view'), 'users'=>array('*'), ), array('allow', // allow authenticated user to perform 'create' and 'update' actions 'actions'=>array('create','update'), 'users'=>array('@'), ), array('allow', // allow admin user to perform 'admin' and 'delete' actions 'actions'=>array('admin','delete'), 'users'=>array('admin'), ), array('deny', // deny all users 'users'=>array('*'), ), ); } Thats the default setting, where anyone can perform index and view actions, meaning that anyone can list all records or view individual records in the associated Model. The next section allows any logged-in user to perform create and update actions. Next, only administrators can perform admin and delete actions. Finally, a global deny for all users is added, to cover any situation that wasnt explicitly defined. This is just a good security practice. Note that these rules just apply to this Controller; each Controller needs its own rules. Youll want to customize the rules to each Controller and situation. For example, I did a site with a subscription system, represented by a Contact Model. In that case, anyone had to be allowed to create new Contact records but only the admin was allowed to list or show Contact records. Generally, though, I think most Controllers would allow everyone to perform show and list actions. You can also create more sophisticated conditionals to create permissions, but that will be a subject for another post. For example, on one project I did, any logged-in user could create certain types of content but they could only update and delete records that they themselves created. Or you could allow users show permission only on their own Contact record. Finally, you may need to change your Controllers so that the retrieval of Model records is handled differently. There are a few methods that load records to be used in a View. Some of the methods, like actionView() and actionUpdate(), call a loadModel() method whose job it is to retrieve a single record. Other methods, like actionIndex() and actionAdmin() retrieve every Model record (using a different approach). In these methods, there are a couple of changes you may want to make. For starters, if the Model in question is related to another Model, as defined in the Model classs relations() method (see my post on Models), you can invoke that relation when you retrieve the record(s). For example, this code will retrieve an employee, plus the department for that employee: $model=Employee::model()->with('department')->findByPk((int)$id);

You only want to do this if youll use the related records, of course. You might also tweak the criteria applied to these methods, but that is a big topic. It basically involves adding WHERE SQL conditions to a query. Ill address it in another post but you can also see the Yii documentation, of course. So this makes the eighth post in a series on using the Yii framework, from start to kinda-finish. Ive got a bunch of miscellaneous topics on the subject to post about, but I wont write those up formally as part of this series. To find those, or any other posting on Yii, use the tags at right.

You might also like