Yii for Beginners

41
http://www.yiiframework.com/wiki/250/yii-for-beginners/ Intro 1. Prerequisities 2. MVC - Architecture description 2.1. Controller 2.1.1. Action 2.2. Model 2.3. View 3. What is it framework and why to use it 4. Yii framework 4.1. The demo project and folder structure 5. Using Yii in praxis 5.1. Create demo project and set it up 5.2. Create Database for your project 5.3. How to create your first controller 5.4. View 5.5. Models and using them 6. Your Own SQL 7. THEMES 8. Secured (secret) file download 9. Modules (not Models) 10. Security 11. Recommended software and sites 12. Used links Intro Hello. This is copy of my Yii Tutorial from forum: Total fresher in PHP frameworks and Yii, I don't understand tutorials In the forum you can ask me questions and I will try to answer them. I will also post there new PDF versions (usefull as offline version). The most up to date will always be this wiki. It's easier for me.

description

Yii framework tutorial

Transcript of Yii for Beginners

Page 1: Yii for Beginners

http://www.yiiframework.com/wiki/250/yii-for-beginners/

Intro1. Prerequisities2. MVC - Architecture description2.1. Controller2.1.1. Action2.2. Model2.3. View3. What is it framework and why to use it4. Yii framework4.1. The demo project and folder structure5. Using Yii in praxis5.1. Create demo project and set it up5.2. Create Database for your project5.3. How to create your first controller5.4. View5.5. Models and using them6. Your Own SQL7. THEMES8. Secured (secret) file download9. Modules (not Models)10. Security11. Recommended software and sites12. Used links

Intro

Hello. This is copy of my Yii Tutorial from forum:

Total fresher in PHP frameworks and Yii, I don't understand tutorials

In the forum you can ask me questions and I will try to answer them. I will also post there new PDF versions (usefull as offline version). The most up to date will always be this wiki. It's easier for me.

Give me a few days or weeks and I will completely rewrite and reformat current version of PDF here. It can't be done in one day :-(

I'm writing this tutorial because when I was beginning with Yii I was totally lost. I didn't understand anything. I didn't know why I needed the demo project, where I should place my PHP scripts, what it means MVC, what should the folder structure look like etc. No tutorial for beginners was available.

Page 2: Yii for Beginners

This tutorial is meant for beginners who have never worked with any PHP framework or with Yii. Who are able to create website with standard PHP, MySQL etc., but are completely lost while beginning with Yii.

1. Prerequisities

I suppose the reader is familiar with PHP and databases (DB). He should be able to write SQL query, use DB in PHP and create at least a simple web using PHP, HTML, CSS and DB. If you don’t know anything about PHP and DB, I recommend that you stop reading and have a look at it. And what’s also important is OOP (Object oriented programming). This means classes, overriding functions, using constructor, public and private methods and properties, etc… Can be practiced in PHP, Java, C#, VB.NET …

2. MVC - Architecture description

MVC (Model-View-Controller) is a type of application architecture. It’s used in Yii framework. When your application uses MVC architecture, it is divided into 3 basic parts.

M = Model = Part that defines relations among data in DB and rules that must be followed when saving data to DB. It also gives us tools to read/save data from/to DB.

V = View = Part that is used just to show data to user. It doesn’t write to DB or count difficult things. It just receives data and shows them using HTML, CSS, JS …

C = Controller = Part that processes and changes the data, handles user’s actions, decides, counts, thinks and calls models and views … It simply acts.

Image 1) MVC schema

Notice the arrow directions in picture above. Controller can read/write data from/to database only via Model. Controller also evaluates user inputs, combines it with data, counts new values … and sends outputs and results to the View and DB. View formats given data and shows them. (For example draws table etc.)

Page 3: Yii for Beginners

As we can see, the Controller is the central point. It’s the boss. Whatever you do - Controller processes it and decides what to do next. Asks for appropriate data from DB and does what you wanted to do. We can see that Model and View don’t do anything, unless they are asked to. In some cases, Model and View do not have to be used.

So let’s focus on Controller now.

2.1. Controller

Controller is initiated (and it's code is run) whenever you enter any address in browser. In its code you can read data from POST, GET or SESSION variables, work with DB etc. When you use MVC architecture (in Yii framework), addresses have special format. They include parameter that specifies which controller will be used. (which part of web you want to enter)

Yes, you can have more controllers. Each controller can be used to work in different part of your web. One controller can work with user accounts, another one with products you sell etc. And what does the web address look like when you use MVC?

www.myweb.com/index.php?r=myController

Parameter “r” says that you want to use Controller named “myController”. And here we can see another speciality of MVC (or Yii). Addresses contain only index.php. No other files. All the navigation is done by the “r” parameter and controllers.

2.1.1. Action

Controller can have one or more sub-controllers. Each does something else. If our controller works with users than his one sub-controller can delete users, another one can add users, third one changes (edits) them … These sub-controllers are called Actions. You can (have to) specify action using the “r” parameter. As we saw above, controller was specified like this: “?r=myController”. If our controller had action called “myAction”, and if we wanted to run it, we would write this address:

www.myweb.com/index.php?r=myController/myAction

We can rewrite this address for example like this:

www.myweb.com/index.php?r=users/edit

If you do not specify action and run only controller like this “?r=myController” than the default action will be run. The default action has to be specified in the controller using function actionIndex().

Page 4: Yii for Beginners

2.2. Model

Model is very simple thing in Yii. You don’t have to write a single line of its code, it can be created automatically using command line. Each table in DB has its own model. This model has the same (or similar) name like the table. Each model has 2 important functions. Find data and Save data. That’s all we usually need. When you need to read data from DB to controller you just write something like:

ModelName.FindAll()

and that’s it. No SQL queries, no fetching array (as you would have to do in PHP). That’s the advantage of Yii and its object-oriented access to DB. When you want to write to table, the command looks cca like this:

ModelName.column = value; … ModelName.Save()

That’s it again.

Another thing that the Model provides is relations. These relations enable you to “tunnel” through one table to another. Important are Foreign Keys. Relation is something like SQL Join. When every employee has in its table the ID of his department, you can easily get info about this department by writing something like this:

$employee->department->departmentName

Where $employee is 1 particular employee selected by some criteria, the word department is name of the relation (leading from model of employees to model of departments) and departmentName is column in table of departments.

2.3. View

As I wrote above, view has no intelligence. It just receives data from Controller and shows them. This is the only place where we use HTML, CSS, JavaScript etc. We of course can use FORs, WHILEs, Ifs, models … But the only aim is to show data to user.

Correction: Described View is an ideal view. In praxis it’s sometimes easier for beginners not to send data from Controller to it, but to read data from DB in View (using model) and show then.

3. What is it framework and why to use it

In a shortcut. Framework is a set of functions that can ease your work. Functions are usually grouped into Classes. One example for all. In Yii framework there is available class named CHtml. It’s obvious, that it provides functions for creating

Page 5: Yii for Beginners

HTML code. (Tables, lists, forms...). You don’t have to use HTML and solve its validity. You just call function

echo CHtml::beginForm();

and it creates this html code:

<form method=”post” action=”thisScriptName”>

And why to use frameworks? It makes your work easier. You don’t have to code every single detail, framework does something for you automatically. Yii for example integrates form-validation functions, it handles user logging and much more. You just have to discover its possibilities and learn to work with them. But it’s the hardest thing. (Sometimes it’s faster to create your own function than to try to understand a prepared solution) And that’s why I write this manual. To show some possibilities in one place and in praxis so you won’t have to google the basics.

4. Yii framework

Yii framework has its web and documentation. All you need to do (if you want to use it) is to download and extract it to your localhost-folder. You of course need a PHP and MySQL server (I use WAMP. If you want to try it, turn off Skype for the moment when Wamp is starting. Otherwise it won’t start.)

4.1. The demo project and folder structure ¶

Now you have Yii “installed” (= you copied all files to localhost-folder). And what next? It may look useless now. The best way to become a friend with Yii is to try the Demo project, go through it and look what it’s code looks like. Every manual describes it, but doesn’t explain why you should use the Demo project. I didn’t understand why everybody was pushing me into some boring demo project, while I wanted to do a real one.

The demo project is good because you will see the folder structure, which is important. When you walk through the code and files, you will understand how you can send data from Controller to View or how forms are validated. You will see how works navigation using the “r” parameter etc. So give it a time and play with it for a while. In the future you can create demo projects, automatically generate Models from you DB and change both to meet your requirements. It's quick. Advantage is, that in demo project are created folders, HTML head etc.

These: Hello World, First project and Blog could help you. Manuals describe basic work with Yii like creating demo project, relations among tables etc …

In demo project (as same as in any other Yii project) is important folder "protected". It contains 3 subfolders: models, controllers, views. There are stored PHP scripts that power your web.

Page 6: Yii for Beginners

Models

You will find there only 2 models that are not connected to DB. Demo project does not work with DB at all. These models are more like a definition of logics for HTML forms. When a HTML form is confirmed on webpage, it's content is checked (validated) using rules specified in these models. The validation is done for example in actionContact(). (see bellow)

The validation rules are specified in rules() method. Items of form are defined as properties of model class. Captions for form items are in method attributeLabels(). There is almost no difference between models that are/aren't connected to

DB. They look 99% the same. If your model should work with database, it would not extend class

CFormModel, but CActiveRecord and it would contain method tableName().

Controllers

Actually, you will see only 1 controller - SiteController.php. Open it in any text editor and have a look at methods:

actionIndex() - it only renders view "index" actionContact() - creates a new instance of model ContactForm, assignes it

data from POST and tests them (all of this is described in next chapters) Finally it renders view "contact" and sends it a variable $model as a parameter.

actionLogout() - you can see how to call system variables and methods of Yii and how you can redirect to a different URL.

These are the only important things for you in the controller.

Views

You will see 2 subfolders:

layouts: contains mainly file main.php with definition of the whole website layout, menu items, logo etc.

site: contains views used in SiteController. Take a look at login.php file. This view is called from actionContact() and it receives $model as a parameter. You will see that you can start using this variable without any other definition. Just write $model.

Last important file is "protected/config/main.php". There is definition of DB connection, of your application name etc. You can add lines to this file in order to enable more functions of Yii.

Important for Windows:

To use command line commands mentioned in manuals (you need them to create the demo project and to use the best things Yii offers = mainly models and relations

Page 7: Yii for Beginners

between them), you will have to modify the “environmental variables”. Right click “This computer” choose “Properties”, than “Advanced” tab and click on button “Environmental Variables”.

A new window with 2 list-boxes will appear. In the lower one find row with variable named “Path”. Add to its value something like this: (yii framework folder path and php path)

C:\Program Files\wamp\www\yii\framework ; C:\Program Files\wamp\bin\php\php5.3.0 

Instead of command line you can use GII webpage in your demo project. I write about it bellow, but I do not use it.

5. Using Yii in praxis

(How to run your first YII project)

Here will be examples of commonly used functions, useful tricks etc. These things are hard to be figured out just so.

5.1. Create demo project and set it up

If you are a rookie, first of all, you should create the demo project, set connection to your DB [7] and understand how it works. When you already are a friend with Yii, you could be able to create folder structure just by yourself.

5.2. Create Database for your project

Very important thing is database. You should design it first. Before writing any code. When this is done, you can generate models, views and controllers automatically (using command line or GII webpage). I generate only models because I want to make it my way.

See this. It’s 4th part of a Yii tutorial [8].

In this tutorial [8] is said, how you should name tables and columns to be able to generate relations among tables automatically. But names are not so important. More useful is to declare relations in DB when designing it. If you use PhpMyAdmin, just create a table with foreign keys (FKs) and go to the “Structure” tab and under the list of columns you will find link to relations creation. When you click it a new screen appears and you can set foreign keys (FKs) relations. Or use software mentioned bellow to design whole DB (I recommend). When SQL relations are defined, Yii will recognize them and will automatically create relations among Models. Otherwise you would have to declare these relations manually. Which is not impossible, but more comfortable is to have it in DB definition.

Page 8: Yii for Beginners

5.2.1. DB design tool

Very interesting thing is that relations will be created automatically when you define foreign keys using SQL relations. I recommend for example software “MySQL Workbench” [10] which is freeware. It allows you to design your DB including SQL relations using graphical tool (ER diagram). You can also enter default data to your tables. It’s very comfortable mainly when you need to delete DB and create it again, or when it has to be redesigned. You see everything on one screen.

Image 2) MySQL Workbench in action - ER creation

To create relation between 2 tables, create first the tables. Then you will need only 1 button from the toolbar that’s on the left side of the screen. It’s the one on the bottom. Its caption is “Place relation using existing columns”. No other relations will be needed. Click this button and you will be asked to select FK column in any table. Select it and then click appropriate PK column in another table and you’re done with this relation.

Page 9: Yii for Beginners

When you’re done with DB design, you just have to press Ctrl+G and DB will be exported to your MySQL server.

I recommend that you go to menu Tools / Options and set “History size” to ca 10-30 steps. Default value is 0, which means unlimited number of undo steps. But it slows down the application very very much.

In versions released in year 2011 I noticed their instability under Win XP SP3. So be patient it crashes very often. But luckily, work is not lost.

Page 10: Yii for Beginners

5.2.1. Run Yiic shell or Gii

Yiic shell - console

When your DB is ready, set the DB connection in file yourProject/protected/config/main.php. Than go to your web-project folder using Command line and write command: yiic shell. It will enable the Yii console and you

Page 11: Yii for Beginners

will be able to create model for 1 table like this: model tableName, or for all tables at once like this: model *

You can use command: “crud TableName” to generate administration for our tables. Than you can, of course, change generated forms and web pages to fit your requirements.

Gii

Models, controllers etc. can also be generated using Gii website (without commandline) if it is allowed. I haven't used it but you can. Gii is webpage that comes with Yii framework. In protected/config/main.php you have to uncomment it and enter password for Gii. Than go to you localhost website and run controller gii like this:

localhost/myproject/index.php?r=gii

I think this is all you have to do.

5.2.2. Define relations in models manually

Now, when you created models for all tables, it may be necessary to define relations (if they were not generated automatically or when you need more of them). This can be done using function relations() in model file. see the video, time 12:15 or manual [9].

And what is the relation? As I wrote above, it’s an SQL Join. If you specify Primary key (PK), foreign key (FK) and SQL relations between them, than Yii can then “tunnel” from Employee to his job description using Jobs FK in the Employees table.

When you make relation from list of employees to their jobs and name this relation ‘job’, you can then write this in Controller to get employee’s job:

$Employee = Employees::model()->findByPk($employeeId);$myJobName = $Employee->job->jobName; /*Where:Employees = model of table created using yiic shell. jobName = column in Jobs table. job = relation name.$Employee = 1 returned record from table Employees - only one because we were searching by PK. If we searched using findAll() it would return list of records and it would be necessary to walk through them using foreach. In your model should be cca this function:*/ public function relations(){

Page 12: Yii for Beginners

return array( 'job' => array(self::BELONGS_TO, 'JobsTableName', 'id_job'), );}/*But I’m not sure about the BELONGS_TO. See links and explanations. And as I am never sure, I recommend to specify relations in DB a generate them using command line or Gii.*/

5.3. How to create your first controller

You just need one file in folder: protected/controllers. The file must be named like this: “NameController.php”. First letter of the Name is upper case as same as the first letter of Controller. It’s necessary for Linux servers. Example. You want to create controller named “My first”. The filename will be “MyfirstController.php”. And what’s inside?

<?phpclass MyfirstController extends Controller{ public function actionIndex() { // here is your code for this action } public function actionMyaction() { // here is your code for this action $this->render(‘myview’); } public function getEmployeeName() { } }?>

As you can see, controller is a Class and contains definitions of action and non-action functions. Default and important action is actionIndex(); It’s used when you don’t specify any action in “r” parameter (as mentioned above). You can add any action you want. For example “My action”. The “r” parameter of “actionMyaction” would look like this:

“?r=Myfirst/Myaction”.

What does mean this row?

$this->render(‘myview’);

Page 13: Yii for Beginners

It tells the action to run a view. View is the part of your application, where you use HTML, CSS formatting etc. and it’s used to show anything to user. (You can also try function renderPartial() – can be usefull)

Yii will look for this view in folder Views/Myfirst. Where “Myfirst” is name of controller. Yes, every controller has its own set (folder) of views.

In Yii the view is actually a part of Controller. You can call it in any action and when you write "$this" in view, you are refering to current Controller, its methods and properties. So if there is something that will be common for all views, you can add it to file "protected/components/Controller.php" because all controllers are based on this class.

5.3.1. Controller - Notes from praxis

5.3.1.1. SESSION

In controller (or View), you may want to use a Session so you can send data among scripts without using forms, POST or GET. (Session is a PHP term, use Google to understand) If you want to use session in Yii, you just write this:

Yii::app()->session[“varName”] = $value;

That’s it. Session variable will be automatically registered, session will be started, etc.

5.3.1.2. USING RELATIONS

If you use relations among models, you can access one table from another one using command like this:

$employees = $department->get_employees; //(get_employees = relation name)

You can also specify which employees you want to get - by DB column name:

$employees = $department->get_employees(array('condition'=>'born<1950'))

Or you can join tables and order it by any column:

$subMenuItems = MainMenu::model()->with('relation1.relation2')->findAll(array('condition'=>'id>21 and relation2.tableColumnName = 3', 'order'=>'relation1.tableColumnName'));

Explanation: Model named MainMenu has relation named “relation1” which is pointing to another model (to another table in DB). The target model has relation named “relation2” referring to a third table. Using following command we join 3 tables:

Page 14: Yii for Beginners

MainMenu::model()->with('relation1.relation2')

5.3.1.3. SETTING HTML PAGE TITLE

Every action in every controller does something different. So it’s good to set page title in every action. You can do this by this command:

$this->pageTitle = ‘My page title’

If you want to use your project name in this title or anywhere else, you can use this system variable:

Yii::app()->name

It’s value is set in file: protected/config/main.php

5.4. View

View is a very simple thing so I will just show some "tricks". Html code can be generated semi-automatically using static class CHtml.

5.4.1. Grouped drop down list

In view you can create drop-down-list using standard HTML:

<select name="selectName" id="selectName"><option value="1">item1</option><option value="2">item2</option>…</select>

Or you can use class CHtml:

echo CHtml::dropDownList($name, $select, $data, $htmlOptions);

$name = name that will be used in $_POST when form is send $select = string with selected value $data = content - interesting think, see bellow $htmlOptions = classical array of attributes:

Page 15: Yii for Beginners

$htmlOptions = array('width'=>'100','style'='color:red;')

$data is basically a simple array with “name=>value” pairs. This Array can be created automatically using function:

$data = CHtml::listData( Model::model()->findAll(),'id_item','item_descr' )

Method listData() just generates following array:

array(‘value1’=>’caption1’, ‘value2’=>’caption2’ … )CHtml::listData(array $models, string $valueField, string $textField, string $groupField='')

$models = list of items. It’s clear, you use for example: MyModel::model()->findAll(array(‘condition’=>’id>4’))

$valueField = what column will be used to fill the value of tag $textField = what column will be used to fill the caption of tag groupField = what column will be used for grouping items in drop down list

If you put these things together a drop down list will be drawn. And if you want to group items in it by specified column, it is very easy. Let’s say you have a table of countries and table of continents. Each country belongs to 1 continent = you have relation 1:N from continent to countries and back. In your drop down list you want to see all the countries. But not mixed together. You want them to be grouped by continents like on the picture above.

To do this, you have to join both tables and than specify the grouping column.

// first we create the join and in $record you have complete table of countries and their continents.$records = Country::model()->with('getContinent')->findAll(); $data = CHtml::listData($records,'id_country','country_name','getContinent.continent_name');echo CHtml::dropDownList('myDropDown','',$data);

Note that to specify the "group column" you have to use the relation name to tell YII which column from the joined tables you want. In joined tables are used aliases.

getContinent.continent_name

If you were refering to the "home model" table, you would write only "t.columnName" - in our case to get data from Country table.

5.4.2. Creating links

Here I Will just recommend to use function CHtml::link() to create hypertext links. Otherwise you can experience some problems with www links. To create URLs always use the method like this:

Page 16: Yii for Beginners

echo CHtml::link("text",array('controller/action'));// orecho CHtml::link("text",$this->createUrl('controller/action')); // and whenever you want to create URL leading to a page on your site, use:$this->createUrl('controller/action');

Because URLs can have more formats in Yii and if you change the format (in protected/config/main.php) and use this method, links will be automatically changed too. If you enter them manually, they will stop working.

If you do not specify controller, the current controller will be automatically used.

5.4.3. Sending variables to view

When you want to send something from Controller to a View, you just add 1 parameter to $this->render() method. Like this:

$this->render(‘myview’, array(‘variableName’=>$value));

In the View you can start using variable $variableName.

5.4.4. Send Form using hyperlink + confirm<a onclick="javascript: if(confirm('Really delete?')){ self.document.forms.**formName**.submit()}" onmouseover="style.cursor='Pointer' " >Delete</a>

This will show ordinary hyperlink Delete. When it’s clicked, a JavaScript confirm-box appears. When you click YES, it does what is written in “onclick” section. In this case, a form named “formName” is send to the server. When you put mouse on the Delete caption, your cursor will be changed to classical “hand”.

Don’t forget to use escape characters when writing javascript using php echo. JS requires apostrophes instead of quotes. You can't write this:

<?php echo ‘ ’word-in-apostrophes’ ‘;?>

Apostrophe can be written like this:

<php echo ‘ \' word-in-apostrophes\' ‘; ?>

5.4.5. AJAX - operations on background

On background means doing something without reloading the page. It’s used (e.g.) for checking password difficulty (web page changes the difficulty status as you write longer and longer word into the password textbox). Or Google uses it to whisper you while entering searched phrase.

Page 17: Yii for Beginners

You can use Ajax via jQuery, which is very very good JavaScript framework. I strongly recommend it to everyone.

Second possibility is to use Yii's integrated Ajax. (It also uses jQuery, but you do not have to know JavaScript)

I will show 3 examples I understand now. The first one changes content of a dropDownList based on what you enter into textbox, the second one changes dropDownList based on what you enter into another dropDownList and the 3rd one changes textbox based on what you enter to another textbox.

PS: Sometimes Yii's Ajax does not work in combination with your own JavaScript. Than I use jQuery instead.

5.4.5.1. Textbox → Dropdownlist

Below you can see an example of code in your View. There is a textField which is waiting for you to enter a text. Second item is a dropDownList. It’s empty now. It will be filled when you enter a text into the textField and click somewhere else. Important is the action mentioned in the URL section. This action must be in current controller. It’s the controller you used to draw this view.

View:

echo CHtml::form(); // CHtml::textField($name, $value, $htmlOptions)echo CHtml::textField('myTextField','',array('ajax' =>array('type'=>'POST', //request type'url'=>CController::createUrl('myActionName'), //action to call'update'=>'#updatedDropDownList', // which HTML element to update))); // CHtml::dropDownList($name, $select, $data, $htmlOptions)echo CHtml::dropDownList('updatedDropDownList','',array(), array()); echo CHtml::endForm();

What’s also important is the word update. It says that referred dropDownList will be extended. In our case we will add some option values (rows). And here is the code of the underlying action:

public function actionMyActionName(){// CHtml::tag($tagName, $htmlOptions, $content, $closeTag)echo CHtml::tag('option',array('value'=>'1'), // html params of tagCHtml::encode('hello'), // caption, string may be enough. CHtml::encode() may not be necessary.

Page 18: Yii for Beginners

true // close tag); }

As you can see, this function only prints some text. In our case it’s the new option for dropDownList. Because we told Yii tu update the dropDownList, this printed option will be added to it. Action can of course be more complex. You can access DB via MyModel::model() and check something.. It’s up to you. The only rule is that you have to echo something. You can echo more records (options) for example using “for” cycle.

 How to work in the action with data you entered in the first field will be shown bellow.

5.4.5.2. Dropdownlist → Dropdownlist

Typical example of using this is a situation, when you need to select country in first dropDownList and in the second one you want to see appropriate cities. Both the view and action part are much the same as before.

**echo CHtml::form();** // CHtml::dropDownList($name, $selected, $values, $htmlOptions)echo CHtml::dropDownList('country','',array(1=>'has value I',2=>'has value II'),array('ajax' =>array('type'=>'POST', //request type'url'=>CController::createUrl('myActionName'), //action to call'update'=>'#updatedDropDownList', // which HTML element to update))); // CHtml::dropDownList($name, $select, $data, $htmlOptions)echo CHtml::dropDownList('updatedDropDownList','',array(), array()); **echo CHtml::endForm();**

Tha main difference here is that drop down boxes have to be in a FORM !! Otherwise their vales won't be accessible via POST in action !!

Below is appropriate action.

public function actionMyActionName(){$countryID = $_POST[‘country’]; // IMPORTANT .. this is how you access previously entered data$listOfCities = getCitiesOfState($countryID);foreach ($listOfCities as $city){echo CHtml::tag('option', // tagnamearray('value'=>$cityID), // html params of tag$cityName, // value from the item selected in the first dropdown is in the POST array

Page 19: Yii for Beginners

true // close tag);} }

5.4.5.3. Textbox → Textbox

If we do not want to add values (as shown in case of dropdowns), but replace the whole form item, we will change only 1 word in the view. This is in the case that we want to show some text in a textbox according to what we enter into the first textbox. We then need to replace the whole textbox with a new one containing the text we need.

echo CHtml::form();echo CHtml::textField('myTextField','',array('ajax' =>array('type'=>'POST', //request type'url'=>CController::createUrl('myActionName'), //action to call'replace'=>'#statusTextBox’, // which HTML element to update))); echo CHtml::textField(‘statusTextBox’,'',array()); echo CHtml::endForm();

In this case is important the **replace ** option. It sais that the original textField named statusTextBox will be replaced with a new one with different properties (text).

public function actionMyActionName(){$status = '';if (strlen($_POST[‘myTextField’])<5){$status = 'too small';}else{$status = 'size is OK';}echo CHtml::textField('statusTextBox', $status,array());}

Notice that the name of the new textbox created in Action must be the same as the name of the deleted textbox. Otherwise this action will be done only once.

If something doesn’t work repeatedly (only once per page refresh), try to generate the HTML FORM ITEM (textbox, dropdownlist ... ) in Action in a different way.

Read more at: [12], [13]

Page 20: Yii for Beginners

Following text is not yet formated. It will be!

5.5. Models and using them

5.5.1. BASIC OVERVIEW OF MODEL’S CODE

As I mentioned earlier, model is something that enables you to work with database. More exactly it is a class that extends class CActiveRecord from Yii core. Each model is declared as follows and contains a few default methods – if it was generated automatically.

class MyModel extends CActiveRecord{}

Class is saved in file: protected\models\MyModel.php If you want to read data from DB, you use model for example like this:

$dataFromDb = MyModel::model()->findAll(); // this returns all rows from table that is controlled using model MyModel.

And what means the double-colon :: and arrow ->? Double-colon means that our class MyModel contains static method model(). If you access static methods and static properties, you use :: and if you access methods of instance or property of instance, you do it via arrow -> Example:

$myVariable = new MyClass()$myVariable::myStaticMethod();$myVariable->myMethodOfInstance();

The static function model() is in the model class and looks like this. (Word “parent” refers to CActiveRecord class - your Model is derived from it) You do not need to understand it, just use it.

public static function model($className=__CLASS__){ return parent::model($className);}

Another function of your model must be tableName(). It only returns table name that is managed via this model:

public function tableName(){ return 'nameOfDbTable';}

Third method is function rules()[14]. It is very important function in case that you want to check data entered into a HTML form (for example when editing goods details, filling contact forms etc.) If user enters something wrong he will be warned

Page 21: Yii for Beginners

and no data will be saved or processed. For example if user should enter his email and forgets @ sign, nothing happens if you specify rules well. Rules are automatically created if you generate model class using command line. Yii takes these rules from DB definition. That is why you should create DB before programming. To be more specific – rules just say which attribute should be validated using specified validator. If you have a look bellow, you will see that for example attribute (or column in DB) “user_email” has to be in form of “email”. Attribute “age” has to be integer = without decimal numbers. So now you know 2 validators: email and numerical. But there are more of them, see [14].

public function rules(){ return array( array('users_email', 'email'), array('age', 'numerical', 'integerOnly'=>true), … );}

You can of course create your own validator and use it in a rule. If you want to add rule with name “myrule” than in your model-class create function “myrule()” and to rules enter this: array('my_tested_column', 'myrule'), In demo project you can find this in praxis in file protected/models/LoginForm.php. Next function is relations(). It defines connections to other tables. It is created automatically if you specify PK-FK relations. That’s why I recommend MySQL Workbench for designing DB. See other chapter. Each relation begins with its name than you have to specify “cardinality” (relation 1:1, 1:N, M:N), target model, target PK. [9]

public function relations(){ return array( 'getUsersPosts'=>array(self::HAS_MANY, 'Posts',' author_id '), );}

  And finally last default function attributeLabels() defines labels (descriptions) for table columns.

public function attributeLabels(){ return array( 'id_user => 'Users ID', 'user_name' => 'Name of user', );}

If you change this function so that it doesn’t return just array but also takes into consideration desired language, it can be used to translate captions in forms based on this model. Example:

public function attributeLabels()

Page 22: Yii for Beginners

{ If (Yii::app()->session[“lang”] == 1) { return array( 'id_user => 'Users ID', 'user_name' => 'Name of user', ); } … }

And the best thing is that if you use console (yiic.bat) to generate models than this class will be created automatically for each of your tables. The whole MyModel class will look cca like this:  

class MyModel extends CActiveRecord{ public static function model($className=__CLASS__) { return parent::model($className); } public function tableName() { return 'nameOfDbTable'; } public function rules() { return array( array('users_email', 'email'), array('age', 'numerical', 'integerOnly'=>true), ); } public function relations() { return array( 'getUsersPosts'=>array(self::HAS_MANY, 'Posts',' author_id '), ); } public function attributeLabels() { return array( 'id_user => 'Users ID', 'user_name' => 'Name of user', ); } }

.. And you can add (override) much more usable functions like scopes(), defaultScope(), afterSave(), beforeValidate()  

Page 23: Yii for Beginners

5.5.2. Another usefull methods

5.5.2.1. Scope()

Scopes are very helpful. If I simplify it they allow you to save an SQL command and use it as a function in connection with particular model. Example: $dataFromDb = MyModel::model()->getOnlySomeRows()->findAll(); ¬¬// this returns all rows from table that is controlled by model MyModel and that comply with criteria specified by scope getOnlySomeRows. GetOnlySomeRows() is the scope. Scope [15] is defined like this:

public function scopes() { return array( 'getOnlySomeRows'=>array( 'condition'=>'status=1' ), 'getOtherRows'=>array( 'condition'=>'status=2' ), ); }

And now my experience from praxis: Let’s imagine that you have 2 tables. Table Suppliers and table Users. Each supplier or user can be signed as enabled or disabled. We want to show all enabled suppliers and their enabled users. First we will add scopes to Suppliers and Users models like this. In both models the scope will look the same if there is column “status”. Let’s say that user or supplier is enabled when status is 1.

public function scopes() { return array( 'getEnabled'=>array( 'condition'=>'status=1' ), 'getSupplier'=>array(self::BELONGS_TO, 'Supplier','id_supplier'), // this will be in Users model 'getUsers=>array(self::HAS_MANY, 'Users’,'id_user'), // this will be in Suppliers model ); }

Now we can write this:

$enabledUsers = Users::model()->getEnabled();$enabledSuppliers = Suppliers::model()->getEnabled();

But if we wanted to get all enabled suppliers and their enabled users, we would have to use inner join with conditions. In Yii this can be done by command with() like this:

$ourJoin = Suppliers::model()->getEnabled()->with(array('getUsers:getEnabled'=>array('joinType'=>'INNER JOIN')))->findAll();

Page 24: Yii for Beginners

I was showing this just because of the colon. If you want to specify relation:scope you use colon. It took me long hours to find this out so I am mentioning it here. And also notice how to force the inner join.

5.5.2.2. Default scope

This is the very the same function as scopes(). But in default scope you can define only one scope - without name (not array of scopes). This scope will be used in every query you will make. It is useful for example if you want to add some calculated attribute to your model or if you want users to see only visible goods etc.

public function defaultScope() { return array( 'select'=>array('*','CONCAT(user_firstname,user_surname) as user_complete_name'), );}

This default scope adds to each query-result counted column “user_complete_name”. You than only have to add this column to your model as a property: public $ user_complete_name'; You could of course use also a JOIN in the default scope like this: (probably useless example, just to show that it is possible and how to use it)

public function defaultScope(){ return array( 'with'=>array('getSupplier'), // relation defined in User model 'select'=>array('*', 'CONCAT(getSupplier.supplier_username_prefix,user_username) as user_username_with_prefix' ), );}

  In scopes you can use everything from CDbCriteria [16]. I guess that you could also use scopes in the related tables like this: 'getSupplier:scopeName.supplier_username_prefix' But I am just guessing. And of course everything mentioned here, for default scope, can be used for ordinary scopes too.   5.5.2.3. Other things

1) If you write a part of sql query manually (in “where” parts for example) you will probably want to tell Yii which column belongs to which table. Example of a “where” part:

$something = User::model()->findAll(array(‘where’=>’t.id = 4 and relationName.column = ‘\Paul‘\’))// t = the home table of current model (User model)// relationName = name of relation in your home model

Page 25: Yii for Beginners

The important thing to remember is the “t” that refers to the “home table”. 2) You can use following command to get current name of table. Usable inside a model class – for example in scopes to specify THIS table. $this->_alias

// can be used in a scope like this:'getEnabled'=>array('condition'=>$this->_alias.'.id_status=1'),

3) If you want to see sql query, write something wrong into it. Yii will write the query on the screen:

$something = User::model()->findAll(array(‘where’=>’t.id = a4 and relationName.column = ‘\Paul‘\’))

4) If you use an alias for a column and want to filter records by a condition, do not use “where”, but “having” clause.

6. Your Own SQL

Sometimes it is much easier to create your own SQL query. I measured difference between ActiveRecord query and pure SQL. Pure SQL was 2x faster. Usefull mainly in ajax. So here is a small code that performs your SQL query and returns an array with results:

public static function sqlQuery($sql) { // $sql can be for example: // "SELECT * FROM firstTable join secondTable ON ... GROUP BY ... " $connection = Yii::app()->db; $command = $connection->createCommand($sql); $results = $command->queryAll(); return $results; }

Disadvantage is that you cannot use methods from ActiveRecord. For example validation etc. But it is faster and if you just read from DB, you can try it.

7. THEMES

You may want to skin your web and allow users (or yourself) to change the skins on demand. It’s very easy. In default state (in automatically created demo project) no theme is set or used. Is used some default appearance. This was the first thing that I did not understand To turn a theme on, you have to specify it in file “protected/config/main.php” by adding the 'theme' line:

return array( 'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..', 'name'=>'Hello World !!', 'theme'=>'theme1',…

Page 26: Yii for Beginners

);

It means that this variable is readable using Yii::app()->theme->getName(). You can set it programmatically in an ACTION (not in view!!) like this:

Yii::app()->theme = 'theme1'; // = each user can have (select) different theme

If theme is not set (using config file, or programmatically) then method getName() will throw error! Yii::app()->theme->baseUrl will contain your theme path = you can use it in layout file to address your css files, images etc. To use your theme1, you will have to create a new subfolder in “themes” folder and name it “theme1”. The “themes” folder is placed in the root of your project. In folder “theme1” will be the same structure as in “protected” folder. Create there views and CSS folders. If a theme is set, views and controllers will be taken from your theme folder. If Yii do not find them, tries to look for them in ordinary “views” and “controllers” folders. But controllers and actions can be the same for all themes. There does not have to be a reason to change them. On the other hand, CSS files will be probably different, so create CSS folder in folder of your new theme and put new CSS files in it.

... to be continued ...

8. Secured (secret) file download

Sometimes you want to offer a file to only a LOGGED IN user but don't want him to see it's path. Nobody has to know that you store files in folder: myweb.com/files. Usually links on webs look like this:

<a href="myweb.com/files/my.pdf">download</a>

But if particular files in this folder are for only particular users, there is danger, that some "smart" user will download files that are not for him, because he knows where your data-storage is.

But how to offer a file for download and not to tell users where files are stored? You can't link particular files. You have to "stream" it to user.

It is also good to store file names in DB and save files to your storage only with their IDs. Like this:

myweb.com/files/1.pdfmyweb.com/files/2.doc

etc. IDs are IDs from DB.

At the end, your download links will look like this:

myweb.com/storage/download/123/how-to-do-something.pdf

Page 27: Yii for Beginners

or rewritten like this:

myweb.com/controller/action/GET-ParamName/GET-ParamValue

I think now it's obvious what I want to show.

Your download links won't point to files, but to a specialised action that sends file to user. In this action you can filter users who are allowed to download your file. You can also use accessControll:

http://www.yiiframework.com/doc/guide/1.1/en/topics.auth#access-control-filter

Finally download links look like this:

<a href="myweb.com/storage/download/123/how-to-do-something.pdf">download</a>

The action is in Controller "storage" and is called actionDownload(). It processes GET parameter like this:

$error = false; // no GET parameters if (sizeof($_GET)<=0){ $error=true;} $id = 0; // we take just the first (and the only) GET parameter foreach ($_GET as $id_=>$title_) { $id = $id_; break;} if (empty($id)){ $error = true;} if (!is_numeric($id)){ $error = true;} if (strval(intval($id)) <> strval($id)) {// this is a simple test that checks whether a string represents an integer $error = true;} if ($error)

Page 28: Yii for Beginners

{ $this->redirect( ... );} // now we know that incomming GET parameter was integer// you may have noticed, that it's value was lost:// myweb.com/storage/download/123/how-to-do-something.pdf// $id = 123.

Now you just have to have a look into DB, find filename and path. When this is done, you just write this:

header('Content-Description: File Transfer');header('Content-Type: application/octet-stream');header('Content-Disposition: attachment; filename='.basename($fileName));header('Content-Transfer-Encoding: binary');header('Expires: 0');header('Cache-Control: must-revalidate');header('Pragma: public');header('Content-Length: ' . filesize($fileName));ob_clean();flush();readfile($fileName);exit;

File is downloaded and user doesn't know from where :-)

Instead of readfile() Yii offers CHttpRequest->sendFile(). But it is goot just for small files. Readfile() is better.

And do not forget to put .htaccess file to your storage-folder with this content:

SetHandler enginge_offdeny from all

First line banns to run PHP in this folder, second line denies direct access via browser.

9. Modules (not Models)

Module is a nested Yii project. It's good when you need to have longer path. Not only cars.com/buy/trailer (project/controller/action). But for example: cars.com/forsuppliers/howtosell/cars (project/module/controller/action). Module can have it's own controllers, actions, models.. But it can use models of parent project.

When I tried to run my first module I read the Yii manual at site:

http://www.yiiframework.com/doc/guide/1.1/en/basics.module

Page 29: Yii for Beginners

But (of course) didn't succeed. Yii manuals just don't describe everything that is important. They are just an overview for people, who understand it. So I had to investigate by my self.

It is simple:

You have your original Yii project (project A) If you want to create a new module, create a brand new project using

command line. (project B)

In project A go to folder "protected" and create there folder "modules". In it create nested folder that will have name of your new module. Lets say "forsuppliers".

In your project B go to folder "protected" and copy at least folders: components, controllers, views.

Paste them to your "forsuppliers" folder.

To "forsuppliers" folder add PHP file with name "ForsuppliersModule.php"

To this file enter following text:

<?phpclass ForsuppliersModule extends CWebModule{// Following will be the default controller of your new module// Yii manual doesn't mention this so modules won't work for you without further research.// If you didn't write this line, the default controller would be "DefaultController" or "Default"// http://www.tipstank.com/2010/11/19/change-the-default-controller-of-a-module-in-yii/ public $defaultController = 'Site';}?>

In your project A (the parrent project) open file protected/config/main.php a find section 'modules'. Here you have to add your new module like this:

'modules'=>array( 'forsuppliers'=>array()),

Now you can use the same models like in the parent project and your url is longer: parrentProject/moduleName/controller/action

10. Security

There is one thing I would like to show you. It is very simple, but I didn't realize this security error for quite a long time.

Page 30: Yii for Beginners

Imagine that you are creating an administration for a forum. If a user loges in, he can edit his posts. Not posts of other people. First, he's presented with list of his posts. You surely filter them by "id_user" that is stored in session. If user clicks an item of this list, he will see details of this post and he can change it. This is done using hidden form field with id_post. But I didn’t know that it was so easy to change the value of this hidden field.

To filter posts by id_user I recommend creating a scope in Post model that will return only posts of logged user. Scope can work with the session variable id_user. This scope can be named getCurrentUsersPosts. Filtering than looks like this:

$posts = Post::model()->getCurrentUsersPosts()->findAll();foreach ($posts as $post){// …echo CHtml::activeHiddenField($post,’id_post’);}

By clicking one record, it’s ID is send to server and it shows the detail of it. It works like this:

$post = Post::model()->findByPk($_POST[“id_user”]);

But what if somebody changed the hidden field? Than user will see detail of post that doesn’t belong to him and he will be able to change it.

Solution? … Simple.

Just add here the scope:

$post = Post::model()->getCurrentUsersPosts()->findByPk($_POST[“id_user”]);

Difference?

Edited post will be searched only among allowed records. If user changes the hidden field and the desired post is not his, he will receive error ($post will be empty) and you know exactly what he did.

11. Recommended software and sites

Web creation

MySQL Workbench NetBeans WAMP server Firefox + Firebug extension + HTML validator extension

Page 31: Yii for Beginners

icons (iconfinder, iconarchive, freeiconsweb) - but make sure that icons are freeware! If icon is "free" it doesn't mean it is freeware and that you can use it on web of your employer! I recommend to use only absolutely free icons.

Web page

jQuery

Sites

http://www.w3schools.com/css/default.asp (manual for CSS3, JS, etc) www.php.net (you can search for PHP methods in right upper corner)

Things to think about

SEO optimization of your web Security of your web

12. Used links

[7] Configure Yii:

http://blog.dmcinsights.com/2009/11/03/configuring-yii/

[8] Tables in DB:

http://blog.dmcinsights.com/2009/11/05/creating-models-views-and-controllers-in-yii/

[9] Relations between models:

http://www.yiiframework.com/doc/guide/database.arr

[10] MySQL Workbench

http://dev.mysql.com/downloads/workbench/5.2.html

[11]

http://www.sterlingsavvy.com/tutorials/index.php?t=1&l=10

[12] Ajax Yii documentation

http://www.yiiframework.com/doc/api/CHtml#ajax-detail

[13] Ajax Yii coockbock + discussion !

Page 32: Yii for Beginners

http://www.yiiframework.com/doc/cookbook/24/

[14] Mode: method rules()

http://www.yiiframework.com/doc/guide/1.1/en/form.model

[15] Active Record

http://www.yiiframework.com/doc/guide/1.1/en/database.ar

CDbCriteria (http://www.yiiframework.com/doc/api/1.1/CDbCriteria "http://www.yiiframework.com/doc/api/1.1/CDbCriteria")