Intro (Part 1)
------------------
Hi. This is **first** article with my Yii
v1 tutorial. I had to split it into
more2 articles as there's limited length of texts on Wiki. So once you understand basics, you can read
nextthe 2nd article here: [**Yii for beginners 2**](http://www.yiiframework.com/wiki/462/yii-for-beginners-2 "Yii for beginners 2").
If you are interested in Yii v2, check this out:
[Yii v2 for beginners](https://www.yiiframework.com/wiki/2552/yii-v2-for-beginners)
This tutorial is copy of PDF in my forum:
[Total fresher in PHP frameworks and Yii, I don't understand tutorials](http://www.yiiframework.com/forum/index.php?/topic/6129-total-fresher-in-php-frameworks-and-yii-i-dont-understand-tutorials "Total fresher in PHP frameworks and Yii, I don't understand tutorials")[...]
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?
```php
www.myweb.com/index.php?r=myController
```[...]
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:
```php
www.myweb.com/index.php?r=myController/myAction
```
We can rewrite this address for example like this:
```php
www.myweb.com/index.php?r=users/edit
```[...]
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:
```php
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:
```php
ModelName.column = value;
…[...]
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:
```php
$employee->department->departmentName
```[...]
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 HTML code. (Tables, lists, forms...). You don’t have to use HTML and solve its validity. You just call function
```php
echo CHtml::beginForm();
```
and it creates this html code:
```php
<form method=”post” action=”thisScriptName”>
```[...]
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)
```php
C:\Program Files\wamp\www\yii\framework ; C:\Program Files\wamp\bin\php\php5.3.0
```[...]
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:
```php
localhost/myproject/index.php?r=gii
```[...]
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:
```php
$Employee = Employees::model()->findByPk($employeeId);
$myJobName = $Employee->job->jobName;[...]
Example. You want to create controller named “My first”. The filename will be “MyfirstController.php”.
And what’s inside?
```php
<?php
class MyfirstController extends Controller[...]
```
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:
```php
“?r=Myfirst/Myaction”.
```
What does mean this row?
```php
$this->render(‘myview’);
```[...]
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:
```php
Yii::app()->session[“varName”] = $value;
```[...]
If you use relations among models, you can access one table from another one using command like this:
```php
$employees = $department->get_employees; //(get_employees = relation name)
```
You can also specify which employees you want to get - by DB column name:
```php
$employees = $department->get_employees(array('condition'=>'born<1950'))
```
Or you can join tables and order it by any column:
```php
$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:
```php
MainMenu::model()->with('relation1.relation2')
```[...]
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:
```php
$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:
```php
Yii::app()->name
```[...]
In view you can create drop-down-list using standard HTML:
```php
<select name="selectName" id="selectName">
<option value="1">item1</option>[...]
```
Or you can use class CHtml:
```php
echo CHtml::dropDownList($name, $select, $data, $htmlOptions);
```[...]
- $data = content - interesting think, see bellow
- $htmlOptions = classical array of attributes:
```php
$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:
```php
$data = CHtml::listData( Model::model()->findAll(),'id_item','item_descr' )
```
Method listData() just generates following array:
```php
array(‘value1’=>’caption1’, ‘value2’=>’caption2’ … )
```
```php
CHtml::listData(array $models, string $valueField, string $textField, string $groupField='')
```[...]
To do this, you have to join both tables and than specify the grouping column.
```php
// first we create the join and in $record you have complete table of countries and their continents.
$records = Country::model()->with('getContinent')->findAll();[...]
```
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.
```php
getContinent.continent_name
```[...]
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:
```php
echo CHtml::link("text",array('controller/action'));
// or[...]
When you want to send something from Controller to a View, you just add 1 parameter to $this->render() method. Like this:
```php
$this->render(‘myview’, array(‘variableName’=>$value));
```[...]
### 5.4.4. Send Form using hyperlink + confirm
```php
<a onclick="javascript: if(confirm('Really delete?')){ self.document.forms.**formName**.submit()}" onmouseover="style.cursor='Pointer' " >
Delete[...]
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
<?php echo ‘ ’word-in-apostrophes’ ‘;?>
```
Apostrophe can be written like this:
```php
<php echo ‘ \' word-in-apostrophes\' ‘; ?>
```[...]
View:
```php
echo CHtml::form();
// CHtml::textField($name, $value, $htmlOptions)[...]
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:
```php
public function actionMyActionName()
{[...]
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.
```php
**echo CHtml::form();**
// CHtml::dropDownList($name, $selected, $values, $htmlOptions)[...]
Below is appropriate action.
```php
public function actionMyActionName()
{[...]
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.
```php
echo CHtml::form();
echo CHtml::textField('myTextField','',[...]
```
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).
```php
public function actionMyActionName()
{[...]
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.
```php
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:
```php
$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:
```php
$myVariable = new MyClass()
$myVariable::myStaticMethod();[...]
```
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.
```php
public static function model($className=__CLASS__)
{[...]
```
Another function of your model must be tableName(). It only returns table name that is managed via this model:
```php
public function tableName()
{[...]
Third method is [function rules()](http://www.yiiframework.com/doc/guide/1.1/en/form.model ""). 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 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](http://www.yiiframework.com/doc/guide/1.1/en/form.model "").
```php
public function rules()
{[...]
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. See text about [relations](http://www.yiiframework.com/doc/guide/database.arr "")
```php
public function relations()
{[...]
```
And finally last default function attributeLabels() defines labels (descriptions) for table columns.
```php
public function attributeLabels()
{[...]
```
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:
```php
public function attributeLabels()
{[...]
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:
```php
class MyModel extends CActiveRecord
{[...]
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:
```php
$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](http://www.yiiframework.com/doc/guide/1.1/en/database.ar "") is defined like this:
```php
public function scopes()
{[...]
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.
```php
public function scopes()
{[...]
```
Now we can write this:
```php
$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:
```php
$ourJoin = Suppliers::model()->getEnabled()->with(array('getUsers:getEnabled'=>array('joinType'=>'INNER JOIN')))->findAll();
```[...]
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.
```php
public function defaultScope()
{[...]
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)
```php
public function defaultScope()
{[...]
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:
```php
$something = User::model()->findAll(array(‘where’=>’t.id = 4 and relationName.column = ‘\Paul‘\’))
// t = the home table of current model (User model)[...]
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
```php
// 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:
```php
$something = User::model()->findAll(array(‘where’=>’t.id = a4 and relationName.column = ‘\Paul‘\’))
```[...]
First, you have to create an action that will print the text. It has to be an action as it is called externally just like if you enter it's URL to browser.
```php
public function actionGetHelloWorldByAjax()
{[...]
To include jQuery type to header this: (I recommend to download current version and use it locally)
```php
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>[...]
To include Fancybox, go to their website, download it and put cca this in your header:
```php
<link rel="stylesheet" href="/fancybox/source/jquery.fancybox.css" type="text/css" media="screen" />
<script type="text/javascript" src="/fancybox/source/jquery.fancybox.pack.js"></script>
```
And now evertyhing will be the same as in the previous example. Except for one row in JS code. Instead of alert(data) we will call the Fancybox like this:
```php
$.get('url2action', function(data){
$.fancybox({content:data});[...]
```
Note that data received from the Action are saved in variable with name "data". But you can use any name you want of course. For example:
```php
$.get('url2action', function(html){
$.fancybox({content:html});[...]
### 5.6.3. Sending variables to action via Ajax
As you can see in documentation for jQuery and it's ajax methods, you do not need a form to send data via Ajax to Controller. You can add data to $.get() method like this:
```php
$.get('url2action', { name: "John", time: "2pm" }, function(html){
$.fancybox({content:html});[...]
```
In Action, your data will be available via $_GET variable. And if we are using GET method (not POST), our action can have the same input parameters that are used in $.get() and these will be automatically assigned. Example:
```php
public function actionGetHelloWorldByAjax($name,$time)
{[...]
Again, it's easy:
```php
$(document).ready(function(){
// As ajaxSubmitButton can by used anything that has class "myAjaxSubmitButton" and is inside any form.[...]
### 5.6.5. Rendering a view as a responce to Ajax Call
If you want to render a view and send it back, you have to use renderPartial(), not render() method. Example:
```php
public function actionGetHelloWorldByAjax($name,$time)
{[...]
The easies way is to create a view that renders each row of your table separetly based on ID of particular user. This view returns:
```php
<tr> .. </tr>
```[...]
JS code would look like this:
```php
$.get('editUser', { userId: 1 }, function(html){ // html variable contains code of updated <tr>
$.fancybox.close(); // closes Fancybox[...]
```
And action:
```php
public function actionGetHelloWorldByAjax($userId)
{[...]
```
You can also generate the JS code in action and just evaluate it in browser. You will need JSON object:
```php
$.getJSON('editUser', { userId: 1 }, function(result){ // result variable contains JSON object
eval(result.js) // runs JS code, see action code below[...]
```
And action:
```php
public function actionGetHelloWorldByAjax($userId)
{[...]
### 5.6.7 Important for events
If items are dynamically added/changed (for example our row updated by Ajax), they do not respond to previously defined events because they didn't exist when $(document).ready(function(){}) was called. They have to be registered again or I recommend to use following kind of event definition. It will work always.
```php
$(document.body).on('change', 'img.myAjaxImgButton', function() {
alert("Dynamically added img button was clicked!");[...]
POST is used in the same way:
```php
$.post("editUser",{ userId: 1 },function(html){
alert("POST done: " + html);[...]
```
If you wanted to receive JSON object, you would have to specify it in $.post() method with 4th parameter:
```php
$.post("editUser",{ userId: 1 },function(html){
alert("POST done: " + html);[...]
In PHP you can create this variable like this:
```php
$csrfVar = 'YII_CSRF_TOKEN:"'.Yii::app()->request->csrfToken.'"';
```
And than you just have to paste it among $.post() variables, plus you can add "ajax" variable just for your needs:
```php
$.post("editUser",{ YII_CSRF_TOKEN:"12345678", ajax:1, userId:1 },function(html){
alert("POST done: " + html);[...]
And how to find out in an action whether it is called via Ajax or in a commmon way? You can write this method in PHP:
```php
function isAjax()
{[...]
In this case your html table will look cca like this:
```php
<table>
<tr>[...]
But where to place the FORM that would make the function? Form can't be used, because of HTML validity. It has to be faked in jQuery cca like this:
```php
<script type="text/javascript">
$(document).ready(function(){
$(".rowSubmit").click(function()
{
var serialized = $(this).closest('tr').wrap('<form>').parent().serialize();[...]