## page was renamed from Yii = Yii = Yii is a high-performance PHP framework best for developing Web 2.0 applications. http://www.yiiframework.com/ == Slackware installation == http://www.yiiframework.com/doc/guide/1.1/en/topics.url#hiding-x-23x * cd ~/Downloads * wget https://github.com/yiisoft/yii/releases/download/1.1.15/yii-1.1.15.022a51.tar.gz * cp yii-1.1.15.022a51.tar.gz /vars/www/htdocs * cd /vars/www/htdocs * tar xvzf yii-1.1.15.022a51.tar.gz * cd yii-1.1.15.022a51 * chown apache * -R * chmod 755 /etc/rc.d/rc.httpd * vim /etc/httpd/httpd.conf {{{ DirectoryIndex index.html index.php LoadModule rewrite_module lib/httpd/modules/mod_rewrite.so Include /etc/httpd/mod_php.conf # enable the php module }}} * vim /etc/httpd/vhosts.conf {{{ ServerName localhostyii DocumentRoot "/var/www/htdocs/yii-1.1.15.022a51" Require all granted AllowOverride all }}} * vim /etc/hosts {{{ 127.0.0.1 localhostyii }}} * vim /etc/httpd/php.ini {{{ date.timezone="Europe/Lisbon" }}} * vim /var/www/htdocs/yii-1.1.15.022a51/demos/blog/.htaccess {{{ Options +FollowSymLinks IndexIgnore */* RewriteEngine on RewriteBase /demos/blog # if a directory or a file exists, use it directly RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d # otherwise forward it to index.php RewriteRule . index.php }}} * vim blog/protected/config/main.php {{{ 'urlManager'=>array( 'showScriptName'=>false, }}} * /etc/rc.d/rc.httpd start * Open URL http://localhostyii/demos/blog/index.php * http://localhostyii/demos/blog/post/index == Validation rules ActiveRecord CModel == http://www.yiiframework.com/doc/guide/1.1/en/form.model#declaring-validation-rules We specify the validation rules in the rules() method which should return an array of rule configurations. || '''Alias''' || '''Class''' || ||boolean || CBooleanValidator || ||captcha || CCaptchaValidator || ||compare || CCompareValidator || ||email || CEmailValidator || ||date || CDateValidator || ||default || CDefaultValueValidator || ||exist || CExistValidator || ||file || CFileValidator || ||filter || CFilterValidator || ||in || CRangeValidator || ||length || CStringValidator || ||match || CRegularExpressionValidator || ||numerical || CNumberValidator || ||required || CRequiredValidator || ||type || CTypeValidator || ||unique || CUniqueValidator || ||url || CUrlValidator || {{{#!highlight php public function rules() { return array( array('username, password', 'required'), array('rememberMe', 'boolean'), array('password', 'authenticate'), array('namex', 'length','min'=>14), // min of 14 chars length ); } }}} == Relations ActiveRecord == http://www.yiiframework.com/doc/guide/1.1/en/database.arr#declaring-relationship Override the relations() method of CActiveRecord. Types relationship: * self::BELONGS_TO * self::HAS_MANY * self::HAS_ONE * self::MANY_MANY {{{#!highlight php public function relations() { return array( 'posts'=>array(self::HAS_MANY, 'Post', 'author_id'), 'profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'), ); } }}} == ActiveResource extension == Adapted from http://www.yiiframework.com/extension/activeresource Steps: * Get source code from https://github.com/Haensel/ActiveResource/ * Add the extension to Yii by placing it in your application's extension folder (for example '/protected/extensions') * Edit your applications main.php config file and add 'application.extensions.EActiveResource.*' to your import definitions * Add the configuration for your resources to the main config {{{ 'activeresource'=>array( 'class'=>'EActiveResourceConnection', 'site'=>'http://api.aRESTservice.com', 'contentType'=>'application/json', 'acceptType'=>'application/json', 'queryCacheId'=>'SomeCacheComponent' ) }}} * Create a class extending EActiveResource like this (don't forget the model() method!): ActiveResource implementation: {{{#!highlight php class Person extends EActiveResource { /* The id that uniquely identifies a person. This attribute is not defined * as a property * because we don't want to send it back to the service like a name, surname or * gender etc. */ public $id; public static function model($className=__CLASS__) { return parent::model($className); } /* Define the resource property of this class */ public function rest() { return CMap::mergeArray( parent::rest(), array( 'resource'=>'people', ) ); } /* Let's define some properties and their datatypes*/ public function properties() { return array( 'name'=>array('type'=>'string'), 'surname'=>array('type'=>'string'), 'gender'=>array('type'=>'string'), 'age'=>array('type'=>'integer'), 'married'=>array('type'=>'boolean'), 'salary'=>array('type'=>'double'), ); } /* Define rules as usual */ public function rules() { return array( array('name,surname,gender,age,married,salary','safe'), array('age','numerical','integerOnly'=>true), array('married','boolean'), array('salary','numerical') ); } /* Add some custom labels for forms etc. */ public function attributeLabels() { return array( 'name'=>'First name', 'surname'=>'Last name', 'salary'=>'Your monthly salary', ); } } }}} Sample usage: {{{ /* GET to http://api.example.com/person/1 and populates a single Person model*/ $person=Person::model()->findById(1); /* GET to http://api.example.com/person and populating Person models */ $persons=Person::model()->findAll(); /* create a resource*/ $person=new Person; $person->name='A name'; $person->age=21; $person->save(); POST request. Returns false if the model doesn't validate /* Updating a resource (sending a PUT request) $person=Person::model()->findById(1); $person->name='Another name'; $person->save(); //PUT request. Returns false if the model doesn't validate //or short version Person::model()->updateById(1,array('name'=>'Another name')); /* DELETE a resource */ $person=Person::model()->findById(1); $person->destroy(); //DELETE to http://api.example.com/person/1 //or short version Person::model()->deleteById(1); //setting attributes $person->attributes=$_POST['Person']; if($person->save()) echo 'yipiie'; //model validated and was saved/updated }}} Other methods for EActiveResource: * public function init() * public function setAttribute($name,$value) * public function getAttributesToSend($attributes=null) * protected function beforeSave() * public function sendRequest($uri,$method,$params,$data) == Log == * Yii::log($message, $level, $category); * Yii::log(string $msg, CLogger::LEVEL_INFO , 'application') * Yii::log(string $msg, CLogger::LEVEL_ERROR , 'application') * Yii::log(string $msg, CLogger::LEVEL_ERROR , 'application') Levels: * trace: this is the level used by Yii::trace. It is for tracing the execution flow of the application during development. * info: this is for logging general information. * profile: this is for performance profile which is to be described shortly. * warning: this is for warning messages. * error: this is for fatal error messages. '''Yii::log('logged message');''' , uses info level and saves the data in protected/runtime/application.log . The logging levels for CLogRouter + CFileLogRoute in protected/config/main.php . == Trace == Yii:trace(string $msg, string $category='application') == Sample controller actions Blog demo == Path: http://localhostyii/demos/blog/site/ {{{#!highlight php public function actionRxvalue() { $m = new Tag(); $m->name=$_GET['value']; $m->save(); header('Content-type: application/json'); echo( json_encode( array('value'=>$_GET['value']) ) ); } public function actionDelvalue() { $m = Tag::model()->find('id=:id' , array(':id' => $_GET['value'] ) ); $m->delete(); header('Content-type: application/json'); echo( json_encode( array('value'=>$_GET['value']) ) ); } }}} Javascript AJAX calls {{{#!highlight javascript $(document).ready(function(){ $('#addTag').click(function(){ console.log('Clicked'); $.ajax({ url: '/demos/blog/site/rxvalue', data: {'value':$('#tag').val() }, success: rxSuccess }); } ); $('.delTag').click( delTag ); } ); function delTag(){ $.ajax({ url: '/demos/blog/site/delvalue', data: {'value': $(this).attr('id') }, success: delSuccess }); return false; } function rxSuccess(data){ $('#listx').append('
  • ' + data.value + '
  • '); console.log(data); } function delSuccess(data){ console.log('Delete !' + data.value ); $('li#' + data.value ).remove(); } }}} == CGridView + CArrayDataProvider with pagination, sort and filtering == views/site/test.php: {{{

    Test 1234

    widget('zii.widgets.grid.CGridView', array( 'dataProvider'=>$dp, 'enableSorting'=>true, 'columns'=>array('id','name' ) , 'filter'=>Tag::model() , )) ; ?> }}} models/Tag.php: {{{ public function search(){ if( isset( $_GET[get_class($this)] ) ){ Yii::app()->session['filterId']= trim($_GET[get_class($this)]['id']); Yii::app()->session['filterName']= trim($_GET[get_class($this)]['name']); } $posts = $this->findAll(); // filtering $filtered = array(); $filterId= Yii::app()->session['filterId']; $filterName= Yii::app()->session['filterName']; foreach($posts as $p){ if( strlen($filterId) >0 ){ if(strpos($p->id , $filterId ) !==false) $filtered[]=$p; } if( strlen( $filterName ) >0 ){ if(strpos($p->name, $filterName ) !==false) $filtered[]=$p; } } if( strlen(Yii::app()->session['filterId'])==0 && strlen(Yii::app()->session['filterName'])==0 ) { $filtered=$posts; } $dataProvider=new CArrayDataProvider( $filtered, array( 'pagination'=>array( 'pageSize'=>4, ) , 'id'=>'id', 'sort'=>array('attributes'=>array('id','name') , 'multiSort'=>false ) ) ); return $dataProvider; } }}} controllers/SiteController.php: {{{ public function actionTest() { syslog(LOG_INFO,'actionTest called'); $dp = Tag::model()->search(); $this->render('test', array( 'dp'=>$dp ) ); } }}} == $this in a view == In a view, $this refers to the controller that called render to that view. Get absolute URL inside a view {{{#!highlight php echo( $this->createAbsoluteUrl($this->getRoute() ) ); }}} == Register Javascript file == {{{#!highlight php Yii::app()->getClientScript()->registerScriptFile( Yii::app()->baseUrl . '/js/test.js' ); }}} == Save state in components == http://www.yiiframework.com/doc/api/1.1/CHtml#statefulForm-detail Generates a stateful form tag. A stateful form tag is similar to form except that it renders an additional hidden field for storing persistent page states. You should use this method to generate a form tag if you want to access persistent page states when the form is submitted. == Widget == Widget definition in components/MyWidget.php {{{ render('mywidget' , array( 'titlexxx'=>$this->titley ) ); } } ?> }}} View in components/views/mywidget.php {{{

    My widget !!!!

    }}} Invocation in other view {{{ widget('MyWidget', array('titley'=>' extra text') ); ?> }}} == Error handling == === Fatal error handling === index.php {{{#!highlight php getRequest()->redirect( Yii::app()->baseUrl . '/site/fatalerror' ); } } /*set_error_handler('error_handler'); function error_handler($errno, $errstr){ echo($errstr); } set_exception_handler('exception_handler'); function exception_handler($ex){ echo($ex->getMessage() ); }*/ Yii::createWebApplication($config)->run(); }}} protected/controllers/SiteController.php: {{{#!highlight php public function actionErrorTest() { $val = 10 / 0; } public function actionExceptionTest1() { raise(Exception('Ups')); } public function actionExceptionTest2() { throw new Exception('Ups'); } public function actionFatalerror() { $this->render('fatalerror' ); } }}} views/site/fatalerror.php {{{

    Fatal error ocurred

    }}} '''protected/views/system/exception.php''': {{{

    Exception

    }}} If it desired to use the original exception handler in '''/framework/views/system/exception.php''' rename or delete this file. == Sitemap generator == * cd /tmp * wget http://yii-sitemapgenerator.googlecode.com/files/sitemapgenerator-v0.81a.zip #BSD license * unzip sitemapgenerator-v0.81a.zip * cd sitemapgenerator * mkdir -p /var/www/htdocs/yii-1.1.15.022a51/demos/blog/protected/extensions/sitemapgenerator * cp * -r /var/www/htdocs/yii-1.1.15.022a51/demos/blog/protected/extensions/sitemapgenerator * nano /var/www/htdocs/yii-1.1.15.022a51/demos/blog/protected/config/main.php {{{ // after return array ... 'controllerMap'=>array( 'sitemap'=>array( 'class'=>'ext.sitemapgenerator.SGController', 'config'=>array( 'sitemap.xml'=>array( 'aliases'=>array( 'application.controllers', ), ), ), ), ), // inside components, urlmanager, rules /* sitemap */ array( 'class'=>'ext.sitemapgenerator.SGUrlRule', 'route'=>'/sitemap', // Optional. Default: '/sitemap' ), }}} Info: * http://www.yiiframework.com/extension/sitemapgenerator/ * http://code.google.com/p/yii-sitemapgenerator/wiki/Installation Remove any files inside the folder with the controllers, ending with '''~'''. Access http://localhostyii/demos/blog/sitemap.xml or http://localhostyii/demos/blog/sitemap . === Patch for sitemap extension === * diff -u originalFile newFile > patchFile # patch generation * patch destinationFile patchFile # apply patch Patch for file SitemapGenerator.php: {{{ --- /tmp/sitemapgenerator/SitemapGenerator.php 2011-10-25 18:31:57.000000000 +0100 +++ SitemapGenerator.php 2014-08-19 22:33:39.292021021 +0100 @@ -435,12 +435,15 @@ $raw=array_filter($raw); $data=array(); foreach ($raw as $param) { - list($key,$val)=explode('=',$param,2); + if(is_null($param)===false && strlen(trim($param))>0){ + list($key,$val)=explode('=',$param,2); + + if (empty($val)) + throw new Exception(Yii::t('sitemapgenerator.msg',"Option '{key}' cannot be empty.",array('{key}'=>$key))); + + $data[$key]=$val; + } - if (empty($val)) - throw new Exception(Yii::t('sitemapgenerator.msg',"Option '{key}' cannot be empty.",array('{key}'=>$key))); - - $data[$key]=$val; } return $data; } }}} Issue submitted in http://code.google.com/p/yii-sitemapgenerator/issues/detail?id=4 . == Yii translations in Javascript == http://www.yiiframework.com/extension/jstrans/ http://www.yiiframework.com/extension/jstrans/files/JsTrans.zip Installation: * Download/clone JsTrans in extension folder (folder should be 'JsTrans') * Import the extension in main config: ('ext.JsTrans.*') * cp JsTrans.zip /tmp * cd /tmp * unzip JsTrans.zip * mkdir -p appx/protected/extensions/JsTrans * cd /tmp/JsTrans * cp * -r /home/vborrego/workspace/m2madmin/protected/extensions/JsTrans protected/config/main.php: {{{ 'components'=>array( ... 'jsTrans'=>array( 'class'=>'ext.JsTrans.JsTrans', ), }}} == Sitemap UL and LI == Item.php in controllers: {{{#!highlight php name = $name; $this->childs = []; } function getName(){ return $this->name; } function addChild($child){ $this->childs[]= $child; } function getChilds(){ return $this->childs; } function toString(){ $ret = '
  • ' . $this->name . '
  • '; return $ret; } public static function attachChild($node , $newNode, $parentNodeName){ if( $node->getName() == $parentNodeName ){ $hasNode=false; foreach($node->getChilds() as $child){ if( $child->getName()==$newNode->getName() ){ $hasNode=true; } } if($hasNode==false) $node->addChild($newNode); } else{ foreach($node->getChilds() as $child){ self::attachChild($child , $newNode, $parentNodeName); } } } } ?> }}} Controller action: {{{#!highlight php request->hostInfo . Yii::app()->request->baseUrl; $doc = DOMDOcument::loadXML( file_get_contents( $base . '/sitemap.xml' ) ); $elements = $doc->getElementsByTagName('loc'); $relUrls=[]; foreach($elements as $item){ $relUrls[] = str_replace($base,'', $item->nodeValue ) ; } $root = new Item($base); $nodes[]=$root; foreach($relUrls as $r){ $splitted = split('/',$r); $level=1; $previousName=$base; foreach($splitted as $s){ if( strlen($s) > 0){ Item::attachChild($root, new Item($s) ,$previousName); $previousName=$s; $level++; } } } echo( $root->toString() ); } ?> }}} == Set base URLs for Yii == {{{#!highlight html