Live News for Yii Framework News, fresh extensions and wiki articles about Yii framework. Thu, 19 Jul 2018 21:31:25 +0000 Zend_Feed_Writer 2 (http://framework.zend.com) https://www.yiiframework.com/ [extension] mortezakarimi/yii2-gentelella-rtl Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/mortezakarimi/yii2-gentelella-rtl https://www.yiiframework.com/extension/mortezakarimi/yii2-gentelella-rtl mortezakarimi mortezakarimi Gentelella RTL / قالب راست چین شده مدیریت برای فریمورک Yii2 ====================================================== قالب راست چین مدیریت مخصوص فریمورک Yii2 بر اساس قالب [gentelella-rtl](https://github.com/mortezakarimi/gentelella-rtl). این قالب بر اساس کد موجود در [yii2-gentelella](https://github.com/yiister/yii2-gentelella) پیاده سازی گشته است و شامل بسته‌های کد لازم و تعدادی ویجت و همچنین دارای ساختار قالب مورد نیاز برای پروژه می‌باشد. برای اطلاعات بیشتر در مورد نحوه استفاده از امکانات پکیج به ریپوزیتوری اصلی در این آدرس [yii2-gentelella](https://github.com/yiister/yii2-gentelella) مراجعه فرمایید. روش نصب ------------ بهترین روش نصب با استفاده از [composer](http://getcomposer.org/download/). اجرای دستور زیر ``` php composer.phar require --prefer-dist mortezakarimi/yii2-gentelella-rtl "~1.0.0" ``` یا افزودن ``` "mortezakarimi/yii2-gentelella-rtl": "~1.0.0‍" ``` به بخش `require ` در فایل `composer.json`. در آینده انجام خواهد شد --------------- در آینده نزدیک مستندات اضافه خواهد شد. ]]> 0 [extension] miolae/yii2-markdown-doc Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/miolae/yii2-markdown-doc https://www.yiiframework.com/extension/miolae/yii2-markdown-doc miolae miolae

yii2-markdown-doc

  1. Installation
  2. Configure
  3. Usage

Yii2 module to display the content of all markdown file in a directory and its sub-folder.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist "miolae/yii2-markdown-doc" "2"

or add

"miolae/yii2-markdown-doc": "2"

to the require section of your composer.json file.

Configure

Configure config/web.php as follows

'modules' => [
    ................
    'doc'  => [
        'class' => 'miolae\yii2\doc\Module',
        // Directory to list
        'rootDocDir' => '@app/docs',
        // set false if you don't want to cache generated html, usefull for debugging 
        'cache' => true,
    ]
    ................
],

Usage

To access the doc, go to http://yoursite.com/doc/

]]>
0
[extension] bitcko/yii2-bitcko-mailer Fri, 13 Jul 2018 09:38:24 +0000 https://www.yiiframework.com/extension/bitcko/yii2-bitcko-mailer https://www.yiiframework.com/extension/bitcko/yii2-bitcko-mailer bitcko bitcko

Yii2 Bitcko PHPMailer

  1. Installation
  2. Usage

Bitcko Yii2 PHPMailer use to send emails from your project.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require bitcko/yii2-bitcko-mailer:dev-master

or add

"bitcko/yii2-bitcko-mailer": "dev-master"

to the require section of your composer.json file.

Usage

Once the extension is installed, simply use it in your code by :

  1. Mailer configuration in config/web.php for basic temp or config/main.php for advanced.
<?php
'components'=> [
    ...
'BitckoMailer'=>[
            'class'=>'bitcko\mailer\BitckoMailer',
            'SMTPDebug'=> 2, // 0 to disable, optional
            'isSMTP'=>true, // default true
            'Host'=>'smtp.gmail.com', //optional
            'SMTPAuth'=>true, //optional
            'Username'=>'you google account username', //optional
            'Password'=>'your google account password', //optional
            'SMTPSecure'=>'tls', //optional, tls or ssl
            'Port'=>587, //optional, smtp server port
            'isHTML'=>true, // default true
        ],
            ...
        ]

  1. Controller example:
<?php

namespace app\controllers;

use Yii;

use yii\web\Controller;

class SiteController extends Controller
{
   
  public function actionSend()
     {
 
 
         $params = [
             'from'=>['address'=>'email address','name'=>'name here'],
             'addresses'=>[
                 ['address'=>'email address','name'=>'name here']
             ],
             'body'=>'email body here',
             
              //optional              
              'subject'=>'email subject here',
               //optional
              'altBody'=>'email alt body here',
               //optional
              'addReplyTo'=>[
                  ['address'=>'email address','information'=>'info here']
              ],
               //optional
              'cc'=>[
                  'email address'
              ],
               //optional
              'bcc'=>[
                  'email address'
              ],
              //optional
              'attachments'=>[
                 // ['path'=>'','name'=>'']
              ],
         ];
         
         return Yii::$app->BitckoMailer->mail($params); // return true if mail sent successfully
 
     }
}


]]>
0
[news] Yii 1.1.20 is released Fri, 06 Jul 2018 18:12:52 +0000 https://www.yiiframework.com/news/178/yii-1-1-20-is-released https://www.yiiframework.com/news/178/yii-1-1-20-is-released CeBe CeBe

We are very pleased to announce that Yii Framework version 1.1.20 is released. You can download it at yiiframework.com/download/.

This release is a release of Yii 1.1 that has reached maintenance mode and will, only receive necessary security fixes and fixes to adjust the code for compatibility with PHP 7 if they do not cause breaking changes. This allows you to keep your servers PHP version up to date in the environments where old Yii 1.1 applications are hosted and stay within the version ranges supported by the PHP team. Yii 1.1.20 is compatible with PHP 7.2 that, at the time of this writing, has an announced security support until November 30, 2020.

We recommend to use Yii 2.0 for new projects as well as introducing Yii 2.0 for developing new features in existing Yii 1.1 apps, as described in the Yii 2 guide. Upgrading a whole app to Yii 2.0 will, in most cases, result in a total rewrite so this option provides a way for upgrading step by step and allows you to keep old applications up to date even with low budget.

This release includes a few PHP 7 compatibility fixes and security improvements.

For the complete list of changes in this release, please see the change log. For upgrading, always make sure to read the upgrade instructions, however in this release there are no changes that require changes.

We would like to express our gratitude to all contributors who have spent their precious time helping improve Yii and made this release possible.

To comment on this news, you can do so in the related forum post.

]]>
0
[extension] yarcode/yii2-mailgun-mailer Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/yarcode/yii2-mailgun-mailer https://www.yiiframework.com/extension/yarcode/yii2-mailgun-mailer lagman lagman

Mailgun mailer component for Yii2 framework

  1. Installation
  2. Usage
  3. Licence
  4. Links

Build Status Latest Stable Version Total Downloads License

Mailgun is a transactional email cloud service. Say goodbye to your usual sendmail or postfix MTA problems. You can start sending emails via cloud without writing any line of code.

Installation

The preferred way to install this extension is through composer.

Either run

composer require --prefer-dist yarcode/yii2-mailgun-mailer

or add

"yarcode/yii2-mailgun-mailer": "*"

to the require section of your composer.json.

Usage

Configure YarCode\Yii2\Mailgun\Mailer as your mailer. ` 'mailer' => [

  'class' => \YarCode\Yii2\Mailgun\Mailer::class,
  'domain => 'example.org',
  'apiKey => 'CHANGE-ME',

], Now you can send your emails as usual. $message = \Yii::$app->mailer->compose() ->setSubject('test subject') ->setFrom('test@example.org') ->setHtmlBody('test body') ->setTo('user@example.org');

\Yii::$app->mailer->send($message); `

Licence

MIT

Links

]]>
0
[extension] bitcko/yii2-bitcko-paypal-api Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/bitcko/yii2-bitcko-paypal-api https://www.yiiframework.com/extension/bitcko/yii2-bitcko-paypal-api bitcko bitcko

Yii2 Bitcko PayPal PayPal Api Extension

  1. Installation
  2. Usage

Yii2 Bitcko PayPal Api extension use to integrate simple PayPal payment in your website.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require bitcko/yii2-bitcko-paypal-api:dev-master

or add

"bitcko/bitcko/yii2-bitcko-paypal-api": "dev-master"

to the require section of your composer.json file.

Usage

Once the extension is installed, simply use it in your code by :

  1. Create developer account in PayPal and then create an app. PayPal Developer Dashboard.
  2. Copy and paste the client Id and client secret in params.php file that exists in app config directory:
    <?php
    

return [

'adminEmail' => 'admin@example.com',
'payPalClientId'=>'app client id here',
'payPalClientSecret'=>'app client secret here'

];

3. Configure the extension  in components section in web.php file exists in app config directory: 

```php
<?php
'components'=> [
    ...
 'PayPalRestApi'=>[
            'class'=>'bitcko\paypalrestapi\PayPalRestApi',
            'redirectUrl'=>'/site/make-payment', // Redirect Url after payment
            ]
            ...
        ]

  1. Controller example:
    call first the checkout action that will redirect you to the redirectUrl you mentioned in the previous step,
    in this example ("/site/make-payment")
    
<?php

namespace app\controllers;

use Yii;

use yii\web\Controller;

class SiteController extends Controller
{
   
    public function actionCheckout(){
        // Setup order information array with all items
        $params = [
            'method'=>'paypal',
            'intent'=>'sale',
            'order'=>[
                'description'=>'Payment description',
                'subtotal'=>44,
                'shippingCost'=>0,
                'total'=>44,
                'currency'=>'USD',
                'items'=>[
                    [
                        'name'=>'Item one',
                        'price'=>10,
                        'quantity'=>1,
                        'currency'=>'USD'
                    ],
                    [
                        'name'=>'Item two',
                        'price'=>12,
                        'quantity'=>2,
                        'currency'=>'USD'
                    ],
                    [
                        'name'=>'Item three',
                        'price'=>1,
                        'quantity'=>10,
                        'currency'=>'USD'
                    ],

                ]

            ]
        ];
        
        // In this action you will redirect to the PayPpal website to login with you buyer account and complete the payment
        Yii::$app->PayPalRestApi->checkOut($params);
    }

    public function actionMakePayment(){
         // Setup order information array 
        $params = [
            'order'=>[
                'description'=>'Payment description',
                'subtotal'=>44,
                'shippingCost'=>0,
                'total'=>44,
                'currency'=>'USD',
            ]
        ];
      // In case of payment success this will return the payment object that contains all information about the order
      // In case of failure it will return Null
      return  Yii::$app->PayPalRestApi->processPayment($params);

    }
}


]]>
0
[wiki] An alternative way to ElasticSearch Wed, 04 Jul 2018 20:48:34 +0000 https://www.yiiframework.com/wiki/2255/an-alternative-way-to-elasticsearch https://www.yiiframework.com/wiki/2255/an-alternative-way-to-elasticsearch Necip Necip

This article is for those who have dealt with the complexity of Elasticsearch or any other indexing machines and are looking for an easier way to index the existing database without additional effort.

Why this post?

The amount of data increases every day. As a result, the search in the databases becomes longer and longer. Conventional data structures must be realigned in order to be able to access information more quickly. There are already database systems like Elasticsearch that can do this. However, such systems also have disadvantages.

The most noticeable major drawbacks are:

  • Learning a new query language. SQL won’t get you far or is not flexible enough.
  • The existing programs must be rewritten in order to process the new result sets appropriately.
  • The safety regulations must be defined again.
  • A second database must be set up, which in principle contains the same data.

Who will benefit from this post?

This information is useful for any programmer who wants to integrate an index database into his existing system in a simple way without additional effort.

The basic idea behind Indexing-machines

We will use this simple Table to demonstrate what an Index-machine does

Tablename: object

UID	TITLE	DESCRIPTION
4711	Rudyard Kipling	If you can keep your head when all about you …
4712	John Magee	I have slipped the surly bonds of Earth and danced the skies on laugher-silvered wings …
4713	Wiliam Wordsworth	Ten thousand saw I at a glance, Tossing their heads in sprightly dance…

With this request we can find very specific texts in this single table:

SELECT ID, Title, Description
FROM object
WHERE Description like '%head%'

But what if we want to find ‚%head%‘ in all tables of our database? We have to write a code to do this job for us. This is inefficent and will work very slowy. The idea behind Elasticsearch and other indexing tables is – so far I understood – to break the strings in single tokens. That means in a very easy way that we have to transform the horicontal order of the table into a vertical order.

Tablename: ncp_index

UID	TABLENAME	FIELDNAME	ID	TOKEN
1001	object	Description	4711	if
1002	object	Description	4711	you
1003	object	Description	4711	can
…				
1010	object	Description	4712	I
1011	object	Description	4712	have
1012	object	Description	4712	slipped
…				

We can tokenize any field of any table of our database into the table ncp_index. Now we can find with a single query very fast any (tokenized) word in our hole database.

SELECT Tablenname, Fieldname, Token
FROM ncp_index
WHERE Token like '%head%'

That is the secret of any Index-Searchengine. Yes, the ncp_index table has a lot of redundant data that we can normalize as follows:

Every field is stored in a system table and has a unique id. let us call it field_id Every content of a field has a lot of same words. These words should be stored only once in a separat words-table.

Our ncp_index table looks now so:

UID	FIELD_ID	ID	TOKEN_ID
1001	123	4711	1
1002	123	4711	2
1003	123	4711	31010	123	4712	4
1011	123	4712	5
1012	123	4712	6
…	
		
Systemtable: fields

UID	TABLENAME	NAME
122	object	Name
123	object	Description
…		

Tablename: word

UID	TOKEN
1	if
2	you
3	can
…	

Some basic examples

/**
 * @author ncp <necips@live.de>
 */
class NCPSearch
{
    /**
     * @param $model
     * @param $tablename
     * @param $fieldnames
     */
    public static function delete_ncp_search_item($model, $tablename) {
        $criteria = new CDbCriteria;
        $criteria->condition = "tablename = :tablename " .
                    "AND id = :id ";
        $criteria->params[":tablename"] = $tablename;
        $criteria->params[":id"] = $model->uid;
        NCPIndexModel::model()->deleteAll($criteria);
    }
    /**
     * @param $model
     * @param $tablename
     * @param $fieldnames
     */
    public static function update_ncp_search_item($model, $tablename, $fieldnames) {
        NCPSearch::delete_ncp_search_item($model, $tablename);
        NCPSearch::insert_ncp_search_item($model, $tablename, $fieldnames);
    }
    /**
     * @param $model
     * @param $tablename
     * @param $fieldnames
     */
    public static function insert_ncp_search_item($model, $tablename, $fieldnames) {
        foreach ($fieldnames as $fieldname) {
            $NCP_index_model = new NCPIndexModel("create");
            $NCP_index_model->tablename = $tablename;
            $NCP_index_model->fieldname = $fieldname;
            $NCP_index_model->id = $model->uid;
            $NCP_index_model->save();
            // a very simple way to tokenize the strings!
            $raw = strip_tags($model->{$fieldname});
            $tokens = explode( ' ', $raw);
            foreach ($tokens as $token) {
                $NCP_token_model = new NCPTokenModel("create");
                $NCP_token_model->NCP_index_uid = $NCP_index_model->uid;
                $NCP_token_model->token = $token;
                $NCP_token_model->save();
            }
        }
    }
    /**
     * @param $models
     * @param $tablename
     * @param $fieldnames
     */
    public static function insert_ncp_search_items($models, $tablename, $fieldnames) {
        foreach ($models as $model) {
            NCPSearch::insert_ncp_search_item($model, $tablename, $fieldnames);
        }
    }
}


// main.php:

// initialize ncp_search table once with all tables which has to be indexed in the main function
NCPSearch::insert_ncp_search_items(UserModel::model()->findAll(), "user", ["login", "mail", "name_last", "name_first"]);
NCPSearch::insert_ncp_search_items(DepartmentModel::model()->findAll(), "department", ["title", "description"]);
NCPSearch::insert_ncp_search_items(ObjectModel::model()->findAll(), "object", ["title", "description"]);
  

// model.php:

class Object : Model
{
  function afterSave()  {
    
    
     // insert this code to synchronize the informations on ncp_index
     if ($this->status === ObjectStatus::DELETED)
            NCPSearch::delete_ncp_search_item($this, "object");
        else
            NCPSearch::update_ncp_search_item($this, "object", ["title", "description"]);       
            
    ...
  }
  
  ...
  
}

Conclusion

These are my basic observations on this subject. These are the first steps to a search-engine that can index existing tables so that informations can be found quickly.

Thanks to

Github

https://github.com/Necip8/ncp_search

Homepage https://ncpup.wordpress.com

I hope this information helps you to build your own super search engine!

]]>
0
[extension] johnsnook/yii2-ip-filter Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/johnsnook/yii2-ip-filter https://www.yiiframework.com/extension/johnsnook/yii2-ip-filter johnsnook johnsnook

Ip filtering for Yii2

  1. Installation
  2. Free API Keys
  3. Customization
  4. Importing Existing Apache Access Logs
  5. Screenshots!

This extension gets the visitors ip address, logs the access and checks if it's blacklisted or whitelisted. If it's a blacklist ip address, it redirects them to a blowoff page.

Installation

1. Download

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist johnsnook/yii2-ip-filter "*"

or add

"johnsnook/yii2-ip-filter": "*"

to the require section of your composer.json file.

2. Configure

Once the extension is installed, add 'ipFilter' to the bootstrap section of your configuration file :

    'bootstrap' => [
        'log',
        'ipFilter',
    ],

Then add the bare-minimum module definition `php

'modules' => [
    ...
    'ipFilter' => [
        'class' => 'johnsnook\ipFilter\Module',
    ],
    ...
],

The routes are defined in the Module file as $urlRules.  These can also be redefined in the module definition.  By default, they look like this for prettyUrls:
```php
    'visitor' => '/ipFilter/visitor/index',
    'visitor/index' => '/ipFilter/visitor/index',
    'visitor/blowoff' => '/ipFilter/visitor/blowoff',
    'visitor/<id>' => 'ipFilter/visitor/view',
    'visitor/update/<id>' => 'ipFilter/visitor/update',
3. Update database schema

The last thing you need to do is updating your database schema by applying the migrations. Make sure that you have properly configured db application component and run the following command:

$ php yii migrate/up --migrationPath=@vendor/johnsnook/yii2-ip-filter/migrations

Free API Keys

1) For the map to render in Visitor view, you must have a MapQuest key. Go to https://developer.mapquest.com/plan_purchase/steps/business_edition/business_edition_free/register for a free API key. If you don't have this set, the map won't display.

2) Ipinfo.io limits the number of requests each day to 100 but with a key you can make 1000 a day. Go to https://ipinfo.io/signup for a free API key If you don't have this set, you'll be limited to 100 requests per day.

3) Proxycheck.io limits the number of requests each day to 100 but with a key you can make 1000 a day. Go to https://proxycheck.io/ for a free API key If you don't have this set, you'll be limited to 100 requests per day.

4) Whatismybrowser.com is serious business, so having an API is mandatory to use their service. Go to https://developers.whatismybrowser.com/api/signup/basic for a free API key, but be prepared to provide an "app name" and website. If you don't have this set, no data beyond the basic USER_AGENT string will be captured.

Customization

So, you should be able to go to `http://yoursit.biz/index.php?r=ipFilter/visitor/index``` or, if you have prettyUrl enabled, `http://yoursite.com/visitor``` and see the visitor index.

But you'll probably want to make your own views. If it was me, I'd copy the controller and views to your backend or basic controllers & views directories. But maybe there's some best practices way to do it.

I have left the layout empty so that the pages should be rendered with your layouts/theme.

When you're done getting all your keys, and deciding that there are some controller actions you're not interested in tracking, your module configuration might look something like this: `php

'modules' => [
    ...
    'ipFilter' => [
        'class' => 'johnsnook\ipFilter\Module',
        'ipInfoKey' => 'Not a real key, obviously',
        'proxyCheckKey' => 'Not a real key, obviously',
        'mapquestKey' => 'Not a real key, obviously',
        'blowOff' => 'site/nope',
        'ignorables' => [
            'acontroller' => ['ignore-me', 'ignore-that'],
            'whitelist' => ['127.0.0.1', '24.99.155.86']
        ]
    ],
    ...
],
As you see, you can add a custom 'blowoff' controller action.  The visitor will be passed in so you can display the name and blowoff message.

A couple of things to note here about the 'ignorables' configuration array.  You can add a controller and actions to ignore as well as a whitelist of IP addresses to ignore.  These will not be added to the access log.

Usage
-----



If you want to find out information on the current user, you can get the visitor model from the module and use it like so:
```php
    $visitor = \Yii::$app->getModule('ipFilter')->visitor;
    // give a special hello to people in Atlanta or your ex wife
    if ($visitor->info->city === 'Atlanta' || $visitor->info->ip_address === '99.203.4.238') {
        echo "Your city sucks balls";
    }

Importing Existing Apache Access Logs

To kickstart your visitor data, you can import apache2 logs, as long as you (not www-data) have permissions to view them and they are in the standard apache format.

This is achieved via the very excellent parser library which can be found at https://github.com/kassner/log-parser.

By default, it assumes that your access logs are at '/etc/httpd/logs' since that's where mine are. You can specify another path as the first argument.

The second argument is for specifying which files you'd like to import. By default, it looks for access*. but a comma delimted list with no spaces can be provided instead.

# The default, looks for /etc/httpd/logs/access*
php yii ipFilter/import/logs

# Looks for /my/own/private/idaho/access*
php yii ipFilter/import/logs '/my/own/private/idaho'

# Will process /etc/httpd/log/access_log-20180603 and /etc/httpd/log/access_log-20180610 ONLY.
php yii ipFilter/import/logs '/etc/httpd/logs' access_log-20180603,access_log-20180610

To see it live, check out https://snooky.biz/visitor

Screenshots!

The main screen ipfilter1

Detail visitor view ipfilter2

Updating the name and/or message for a visitor. ipfilter3

The default blocked user view. (As seen from Tor) ipfilter4

]]>
0
[extension] razonyang/yii2-log Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/razonyang/yii2-log https://www.yiiframework.com/extension/razonyang/yii2-log razonyang razonyang

Enhanced DB Target for Yii2 Log Component

  1. Installation
  2. Usage

Packagist Packagist Travis

I wrote this extension for resolving the following problems:

  1. The logs are chaotic, I cannot distinguish which logs are came from the same requests. It is hard to debug in concurrent scenarios.
  2. The yii\log\DbTarget does not provide rotate feature.

Installation

composer require --prefer-dist razonyang/yii2-log

Usage

The usage is similar to yii\log\DbTarget.

Configuration
[
    ...

    'components' => [
        ...
        'log' => [
            'targets' => [
                [
                    'class' => \razonyang\yii\log\DbTarget::class,
                    'levels' => ['error', 'warning'],
                    'logTable' => '{{%log}}',

                    // rotate settings
                    'rotateInterval' => 100000,
                    // rotate mutex settings
                    'rotateMutex' => 'mutex',
                    'rotateMutexKey' => 'log_rotate',
                    'rotateMutexAcquireTimeout' => 0,
                ],
            ],
        ],

        // mutex is required by log rotate.
        'mutex' => [
            'class' => \yii\mutex\FileMutex::class,
        ],
        ...
    ],

    ...

    // migrate and rotate settings for console application.
    'controllerMap' => [
        'migrate' => [
            'class' => \yii\console\controllers\MigrateController::class,
            'migrationPath' => [
                ...
                '@vendor/razonyang/yii2-log/src/migrations',
                ...
            ],
        ],
        'log' => [
            'class' => \razonyang\yii\log\LogController::class,
        ]
    ],

    ...
]
Migrate
./yii migrate
Rotate
./yii log/rotate
]]>
0
[extension] zertex/yii2-avatar-generator Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/zertex/yii2-avatar-generator https://www.yiiframework.com/extension/zertex/yii2-avatar-generator zertex zertex

Avatar Generator

  1. Features
  2. Dependencies
  3. Installation
  4. Configuration
  5. Using
  6. Screenshot
  7. Examples

Generate avatar for user by his name, file or url for Yii2.

Latest Stable Version Total Downloads

Features

  • Generate avatar by username
  • Generate avatar from file or url (http only)
  • Auto select background color by username
  • Contrast color for text
  • Font face and size customize
  • Texture for background (2 available now)

Dependencies

  • PHP 7
  • PHP GD
  • zertex/avatar-generator

Installation

Install with composer:

composer require zertex/yii2-avatar-generator

or add

"zertex/yii2-avatar-generator": "*"

to the require section of your composer.json file.

Configuration

Add to common/config/main.php or config/web.php

'components' => [
    ...
    'avatar' => [
        'class' => \zertex\avatar_generator\AvatarGenerator::class,
        'images_folder' => 'path_to_image_files',
        'images_url' => 'url_to_image_files',
        'size_width' => 300,            // default: 300
        'font' => 'path_to_ttf_font',   // default: Play-Bold // may use aliases
        'font_size' => 200,             // default: 200
        'salt' => 'random_salt',        // salt for image file names
        'texture' => ['sun', 'rain'],   // texture name
        'text_over_image' => true,      // draw text over image (for avatar from file)
        'texture_over_image' => true,   // draw texture over image (for avatar from file)
    ],
],
  • images_folder - required Folder for images
  • images_url - required Url to folder with images
  • size_width - Origin image side width. Default: 300
  • font - Path to TTF font file. Yii2 aliases ready. Default: Play-Bold.ttf
  • font_size - Font size. Default: 300
  • salt - Random garbage for images file name
  • texture - Texture name: sun, rain. Default: empty
  • text_over_image - Draw text over image. For avatar created from file. Default: true
  • texture_over_image - Draw texture over image. For avatar created from file. Default: true

Using

Yii::$app->avatar->show('username', [width], [file or url], [new_file_name]);

Simple use with default image resolution `html <?= Yii::$app->avatar->show('John Smith') ?> `

Image with 150 px sides `html <?= Yii::$app->avatar->show('John Smith', 150) ?> `

Image for existing file with default image resolution `html <?= Yii::$app->avatar->show('John Smith', null, '/path/JM_Avatar.jpg') ?> orhtml <?= Yii::$app->avatar->show('John Smith', null, 'http://site.org/JM_Avatar.jpg') ?> `

Image for existing file with 150 px sides `html <?= Yii::$app->avatar->show('John Smith', 150, '/path/JM_Avatar.jpg') ?> `

Using without Yii2 wrap

You can use avatar generator without Yii2 wrap. Just install https://github.com/zertex/avatar-generator

Screenshot

alt text

Examples

https://zertex.ru/yii2-avatar-generator

]]>
0
[extension] microinginer/yii2-dropdown-action-column Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/microinginer/yii2-dropdown-action-column https://www.yiiframework.com/extension/microinginer/yii2-dropdown-action-column microinginer microinginer

Alternative yii\grid\ActionColumn for yii2

  1. Default buttons
  2. Custom buttons
  3. Install

Russian readme

Default buttons

echo \yii\grid\GridView::widget([
    ...
    'columns'      => [
        ...
        [
            'class' => \microinginer\dropDownActionColumn\DropDownActionColumn::className(),
        ],
    ],
]);

alternative yii\grid\ActionColumn default buttons

Custom buttons

echo \yii\grid\GridView::widget([
    ...
    'columns'      => [
        ...
        [
            'class' => \microinginer\dropDownActionColumn\DropDownActionColumn::className(),
            'items' => [
                [
                    'label' => 'View',
                    'url'   => ['view'],
                ],
                [
                    'label' => 'Export',
                    'url'   => ['expert'],
                ],
                [
                    'label'   => 'Disable',
                    'url'     => ['disable'],
                    'linkOptions' => [
                        'data-method' => 'post'
                    ],
                ],
            ]
        ],
    ],
]);

alternative yii\grid\ActionColumn custom buttons

Install

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist microinginer/yii2-dropdown-action-column "dev-master"

or add

"microinginer/yii2-dropdown-action-column": "dev-master"

to the require section of your composer.json file.

]]>
0
[extension] microinginer/yii2-cbrf-rates Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/microinginer/yii2-cbrf-rates https://www.yiiframework.com/extension/microinginer/yii2-cbrf-rates microinginer microinginer

yii2-cbrf-rates

Экстеншен yii2 для получения курса валют в рублях. Источник данных Центробанк Российской Федерации

Установка

Предпочтительный способ установки composer.

Запустите комманду

php composer.phar require --prefer-dist microinginer/yii2-cbrf-rates "dev-master"

или добавьте

"microinginer/yii2-cbrf-rates": "dev-master"

в раздел require в вашем composer.json файле.

В конфигурационном файле добавляем: `php $config = [

...
'components' => [
    ...
    'CbRF' => [
        'class' => 'microinginer\CbRFRates\CBRF',
        'defaultCurrency' => "EUR"
    ],
    ...
]
...

] `

Примеры работы

// ------------------------------------------------------------------------------------------------------------------------
// Вызов метода all() без вызова других методов возврошает все курсы на текущее время
print_r(Yii::$app->CbRF->all());
/*
Результат работы

Array
(
    ...
    [USD] => Array
        (
            [name] => Доллар США
            [value] => 59.7665
            [char_code] => USD
            [num_code] => 840
            [nominal] => 1
            [id] => R01235
        )
    ...
)
*/
// ------------------------------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------------------------------
// Вызов метода one() без вызова других методов возврошает курс по умолчаню, указанный в конфиге
print_r(Yii::$app->CbRF->one());

/*
//Результат работы
Array
(
    [name] => Евро
    [value] => 65.9882
    [char_code] => EUR
    [num_code] => 978
    [nominal] => 1
    [id] => R01239
)
*/
// ------------------------------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------------------------------
// Возвращает все курсы валют для указанной даты
print_r(Yii::$app->CbRF->filter(['date' => time()-(86400*7)]))->all(); 
// ------------------------------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------------------------------
// Возвращает курс валюты по умолчанию для указанной даты
print_r(Yii::$app->CbRF->filter(['date' => time()-(86400*7)]))->one(); 
// ------------------------------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------------------------------
// Возврощает все курсы валют указанный в параметре currency
print_r(Yii::$app->CbRF->filter(['currency' => 'usd, aud, eur']))->all(); 
// ------------------------------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------------------------------

//Вызов метода short()
print_r(Yii::$app->CbRF->short()->all());
/*
Резлуьтат запроса
Array
(
    ...
    [HUF] => 0.21349
    [DKK] => 8.8581
    [USD] => 59.7665
    [EUR] => 65.9882
    [INR] => 0.93502
    [KZT] => 0.318891
    [CAD] => 46.1304
    ...
)
*/
// ------------------------------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------------------------------
// Пример получения динамики котировок 
print_r(
    Yii::$app
        ->CbRF
        ->filter(['currency' => 'usd, aud, eur']))
        ->withDynamic(['date_from' => '20.05.2015', 'date_to' => '25.05.2015'])
        ->all()
); 
/*
//Резлуьтат запроса
Array
(
    ...
    [USD] => Array
        (
            [name] => Доллар США
            [value] => 59.7665
            [char_code] => USD
            [num_code] => 840
            [nominal] => 1
            [id] => R01235
            [dynamic] => Array
                (
                    [0] => Array
                        (
                            [date] => 1432080000
                            [value] => 49.1777
                        )

                    [1] => Array
                        (
                            [date] => 1432166400
                            [value] => 49.7919
                        )

                    [2] => Array
                        (
                            [date] => 1432252800
                            [value] => 49.9204
                        )

                    [3] => Array
                        (
                            [date] => 1432339200
                            [value] => 49.7901
                        )

                )

        )
    ...
)
*/
// ------------------------------------------------------------------------------------------------------------------------
]]>
0
[extension] slavkovrn/yii-prettyphoto Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/slavkovrn/yii-prettyphoto https://www.yiiframework.com/extension/slavkovrn/yii-prettyphoto Viacheslav Kolesnikov Viacheslav Kolesnikov

PrettyPhoto image galary widget for Yii 1 Framework

  1. Installation
  2. Usage

The extension uses jQuery PrettyPhoto and makes image galary from php array of structure defined.

PrettyPhoto image galary PHP Array generator.

PrettyPhoto image galary

Installation

The preferred way to install this extension is through composer.

Either run:

composer require slavkovrn/yii-prettyphoto:dev-master

or add

"slavkovrn/yii-prettyphoto": "dev-master"

to the require section of your composer.json file.

Usage

Set link to extension in your view:

<?php $this->widget(slavkovrn\prettyphoto\PrettyPhotoWidget::class,[
    'id'     =>'prettyPhoto',   // id of plugin should be unique at page
    'images' => [               // images at popup window of prettyPhoto galary
        1 => [
                'src' => 'http://yii2.kadastrcard.ru/uploads/prettyphoto/image1.jpg',
                'thumb' => 'http://yii2.kadastrcard.ru/uploads/prettyphoto/image1.jpg',
                'title' => 'Image visible in widget',
            ],
        2 => [
                'src' => 'http://yii2.kadastrcard.ru/uploads/prettyphoto/image2.jpg',
                'thumb' => 'http://yii2.kadastrcard.ru/uploads/prettyphoto/image2.jpg',
                'title' => 'image 1',
            ],
        3 => [
                'src' => 'http://yii2.kadastrcard.ru/uploads/prettyphoto/image3.jpg',
                'thumb' => 'http://yii2.kadastrcard.ru/uploads/prettyphoto/image3.jpg',
                'title' => 'image 2',
            ],
        4 => [
                'src' => 'http://yii2.kadastrcard.ru/uploads/prettyphoto/image4.jpg',
                'thumb' => 'http://yii2.kadastrcard.ru/uploads/prettyphoto/image4.jpg',
                'title' => 'image 3',
            ],
    ]
]); ?>

write comments to admin

]]>
0
[extension] motion/yii2-language-provider Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/motion/yii2-language-provider https://www.yiiframework.com/extension/motion/yii2-language-provider greeflas greeflas

Language provider interface

  1. Installation
  2. Usage
  3. Tests
  4. Licence

This package provides interface for language provider for accessing application languages from any storage for Yii2 Framework. It's allows to you create multi-language modules for using in Yii2 based application. As example of integration to module you can see yii2-email-template extension.

Build Status Scrutinizer Code Quality Total Downloads Latest Stable Version Latest Unstable Version

From the box you can use:

If you want to create your implementation of language provider you should implement interface motion\i18n\LanguageProviderInterface.

Installation

The preferred way to install this extension is through composer.

Either run

$ composer require motion/yii2-language-provider

or add

"motion/yii2-language-provider": "~2.1"

to the require section of your composer.json.

Usage

Config language provider
Option Description Type Default
languages Should contains list of application languages. array []
defaultLanguage Should contains default application language. array []
Example
$config = [
    'languages' => [
        [
            'label' => 'English',
            'locale' => 'en',
        ],
        [
            'label' => 'Ukrainian',
            'locale' => 'uk',
        ],
        [
            'label' => 'Russian',
            'locale' => 'ru',
        ],
    ],
    'defaultLanguage' => [
        'label' => 'English',
        'locale' => 'en',
    ],
];

$provider = new \motion\i18n\ConfigLanguageProvider($config);
$provider->getLanguages(); // returns list of languages
$provider->getDefaultLanguage(); // returns default language
$provider->getLanguageLabel('en'); // returns language label by locale (`English`)
Database language provider
Option Description Type Default
db Database connection instance. string, array, \yii\db\Connection db
tableName Name of language entity in database. string language
localeField Name of locale field in language entity. string locale
labelField Name of label field in language entity. string label
defaultField Name of field in table with default language flag. string is_default
Example
$config = [
    'db' => 'secondDb',
    'labelField' => 'title',
];
$provider = new \motion\i18n\DbLanguageProvider($config);
$provider->getLanguages(); // returns list of languages
$provider->getDefaultLanguage(); // returns default language
$provider->getLanguageLabel('uk'); // returns language label by locale

Tests

You can run tests with composer command

$ composer test

or using following command

$ codecept build && codecept run

Licence

License

This project is released under the terms of the BSD-3-Clause license.

Copyright (c) 2017-2018, Motion Web Production

]]>
0
[news] Yii adopts SemVer since version 3.0.0 Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/news/177/yii-adopts-semver-since-version-3-0-0 https://www.yiiframework.com/news/177/yii-adopts-semver-since-version-3-0-0 samdark samdark

Since version 3.0.0 Yii adopts SemVer versioning to achieve better predictability and compatibility with Composer.

Same will happen with extensions. They will adopt SemVer starting from next major versions.

SemVer is simple. Given a version number MAJOR.MINOR.PATCH, increment the:

  • MAJOR version when you make incompatible API changes,
  • MINOR version when you add functionality in a backwards-compatible manner, and
  • PATCH version when you make backwards-compatible bug fixes.

Yii 2.0.x versioning stays as is.

]]>
0
[extension] timurmelnikov/yii2-loading-overlay Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/timurmelnikov/yii2-loading-overlay https://www.yiiframework.com/extension/timurmelnikov/yii2-loading-overlay timurmelnikov timurmelnikov

Yii2 виджет-обертка для jQuery LoadingOverlay

  1. Скриншоты
  2. Демонстрация работы
  3. Установка
  4. Использование
  5. Настройки

Latest Stable Version Latest Unstable Version Total Downloads License

Виджет предназначен для наложения картинки-лоадера на блок, при обработке Ajax запроса.

Скриншоты

Наименование Скриншот Настройки
Pjax с Gridview Pjax с Gridview'color'=> 'rgba(102, 255, 204, 0.2)', 'fontawesome' => 'fa fa-spinner fa-spin'
Pjax с произвольным блоком Pjax с произвольным блоком'color'=> 'rgba(255, 102, 255, 0.3)'

Демонстрация работы

Demo страничка jQuery LoadingOverlay

Установка

Запустить команду json php composer.phar require --prefer-dist timurmelnikov/yii2-loading-overlay "~1.0.0"

Добавить в секцию "require" файла composer.json: ` json {

"require": {
    "timurmelnikov/yii2-loading-overlay": "~1.0.0"
}

} ` После добавления, выполнить команду: composer update

Использование

Есть 2 способа использования:

1-й - просто подключаем jQuery LoadingOverlay к представлению

В представлении, где будет использоваться yii2-loading-overlay, подключить: php timurmelnikov\widgets\LoadingOverlayAsset::register($this);

Далее, использовать обычный JavaScript, для отображения/скрытия jQuery LoadingOverlay, руководствуясь документацией jQuery LoadingOverlay, например так: ` php <?php

//Код на JavaScript (heredoc-синтаксис) $script = <<< JS

//Настройки (можно не использовать, тогда - все по умолчанию)
$.LoadingOverlaySetup({
    color           : "rgba(0, 0, 0, 0.4)",
    maxSize         : "80px",
    minSize         : "20px",
    resizeInterval  : 0,
    size            : "50%"
});

//Наложение jQuery LoadingOverlay на элемент с ID #p0, при отправке AJAX-запроса
$(document).ajaxSend(function(event, jqxhr, settings){
    $("#p0").LoadingOverlay("show");
});

//Скрытие jQuery LoadingOverlay на элемент с ID #p0, после выполнения AJAX-запроса
$(document).ajaxComplete(function(event, jqxhr, settings){
    $("#p0").LoadingOverlay("hide");
});

JS;

//Подключение скрипта в представлении $this->registerJs($script, yii\web\View::POS_READY);

?> `

2-й - работа с Pjax

Класс LoadingOverlayPjax, является расширением стандартного yii\widgets\Pjax и наследует все его поведение.

В представлении, где будет использоваться Pjax, подключить: php use timurmelnikov\widgets\LoadingOverlayPjax;

Использовать, вместо стандартного Pjax, "оборачивая" в него, например GridView (Скриншот 1): ` php <?php LoadingOverlayPjax::begin([ 'color'=> 'rgba(102, 255, 204, 0.2)', 'fontawesome' => 'fa fa-spinner fa-spin' ]); ?>

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],
        'id',
        'name',
        'phone',
        ['class' => 'yii\grid\ActionColumn'],
    ],
]); ?>

<?php LoadingOverlayPjax::end(); ?> `

Настройки

Для настроек, использовать публичные свойства класса LoadingOverlayPjax, например: ` php <?php LoadingOverlayPjax::begin([

'color'=> 'rgba(255, 255, 44, 0.8)', //Настраиваем цвет
'elementOverlay' => '#element'       //Картинка лоадера, наложится на DOM элемент с id="element"

]); ?> ... <?php LoadingOverlayPjax::end(); ?> `

Перечень настроек (свойств)
Свойство Описание
color Свойство CSS background-color в формате rgba()
fade Управление появлением / затуханием
fontawesome Классы иконок Font Awesome (необходим Font Awesome, например - https://github.com/rmrevin/yii2-fontawesome)
image URL картинки
imagePosition" Свойство CSS background-position, для настройки расположения изображения
maxSize Максимальный размер в пикселях
minSize Минимальный размер в пикселях
size Размер изображения в процентах
zIndex Свойство CSS z-index
elementOverlay Альтернативный DOM элемент наложения jQuery LoadingOverlay

Примечание: Свойство "fontawesome" , имеет более высокий преоритет, чем свойство "image". Если установлены 2 настройки "image" и "fontawesome", "image" - игнорируется, "fontawesome" - отображается.

]]>
0
[extension] inquid/yii2-tensorflow-js Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/inquid/yii2-tensorflow-js https://www.yiiframework.com/extension/inquid/yii2-tensorflow-js gogl92 gogl92

Tensorflow JS Yii2 integration

  1. Installation
  2. Usage

Widgets and useful stuff to use tensorflow js on Yii2 alt text

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist inquid/yii2-tensorflow-js "*"

or add

"inquid/yii2-tensorflow-js": "*"

to the require section of your composer.json file.

Usage

Once the extension is installed, simply use it in your code by :

<?= \inquid\tensoflowjs\TensorflowWidget::widget(['x1'=>[1, 2, 3, 4],'x2'=>[1, 3, 5, 7],'y1'=>[4,1],'y2'=>[4,1],'epochs'=>11]); ?>

You can use this video as guide to understand how Tensorflow works: Video

Here is the example of the video: `php

<?= \inquid\tensorflowjs\TensorflowWidget::widget(['x1'=>[-1,0,1,2,3,4],'x2'=>[-3,-1,1,3,5,7],'y1'=>[6,1],'y2'=>[6,1],'epochs'=>500,'testDataX' => [20],'testDataY' => [1,1]]); ?>

]]>
0
[extension] bitcko/yii2-bitcko-google-calendar-api Thu, 14 Jun 2018 11:10:44 +0000 https://www.yiiframework.com/extension/bitcko/yii2-bitcko-google-calendar-api https://www.yiiframework.com/extension/bitcko/yii2-bitcko-google-calendar-api bitcko bitcko

Yii2 Bitcko Google Calendar Api Extension

  1. Installation
  2. Usage

Yii2 Bitcko Google Calendar Api Extension use to create and delete events from google calendar

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require bitcko/yii2-bitcko-google-calendar-api:dev-master

or add

"bitcko/bitcko/yii2-bitcko-google-calendar-api": "dev-master"

to the require section of your composer.json file.

Usage

Once the extension is installed, simply use it in your code by :

  1. Download client_secret.json file from Google Developer Console.
  2. Move the client_secret.json to app/web dir.
  3. Controller example
<?php

namespace app\controllers;
use yii\helpers\Url;
use yii\web\Controller;

use bitcko\googlecalendar\GoogleCalendarApi;

/**
 * GoogleApi controller.
 *
 * @package app\controllers
 * @author  Mhmd Backer shehadi (bitcko) <www.bitcko.com>

 */
class GoogleApiController extends Controller
{


    public function actionAuth(){

        $redirectUrl = Url::to(['/google-api/auth'],true);
        $calendarId = 'primary';
        $username="any_name";
        $googleApi = new GoogleCalendarApi($username,$calendarId,$redirectUrl);
        if(!$googleApi->checkIfCredentialFileExists()){
            $googleApi->generateGoogleApiAccessToken();
        }
        \Yii::$app->response->data = "Google api authorization done";
    }
    public function actionCreateEvent(){
        $calendarId = 'primary';
        $username="any_name";
        $googleApi = new GoogleCalendarApi($username,$calendarId);
        if($googleApi->checkIfCredentialFileExists()){
            $event = array(
                'summary' => 'Google I/O 2018',
                'location' => '800 Howard St., San Francisco, CA 94103',
                'description' => 'A chance to hear more about Google\'s developer products.',
                'start' => array(
                    'dateTime' => '2018-06-14T09:00:00-07:00',
                    'timeZone' => 'America/Los_Angeles',
                ),
                'end' => array(
                    'dateTime' => '2018-06-14T17:00:00-07:00',
                    'timeZone' => 'America/Los_Angeles',
                ),
                'recurrence' => array(
                    'RRULE:FREQ=DAILY;COUNT=2'
                ),
                'attendees' => array(
                    array('email' => 'lpage@example.com'),
                    array('email' => 'sbrin@example.com'),
                ),
                'reminders' => array(
                    'useDefault' => FALSE,
                    'overrides' => array(
                        array('method' => 'email', 'minutes' => 24 * 60),
                        array('method' => 'popup', 'minutes' => 10),
                    ),
                ),
            );

           $calEvent = $googleApi->createGoogleCalendarEvent($event);
            \Yii::$app->response->data = "New event added with id: ".$calEvent->getId();
        }else{
            return $this->redirect(['auth']);
        }
    }


    public function actionDeleteEvent(){
        $calendarId = 'primary';
        $username="any_name";
        $googleApi = new GoogleCalendarApi($username,$calendarId);
        if($googleApi->checkIfCredentialFileExists()){
            $eventId ='event_id' ;

             $googleApi->deleteGoogleCalendarEvent($eventId);
            \Yii::$app->response->data = "Event deleted";
        }else{
            return $this->redirect(['auth']);
        }
    }

    public function actionCalendarsList(){
        $calendarId = 'primary';
        $username="any_name";
        $googleApi = new GoogleCalendarApi($username,$calendarId);
        if($googleApi->checkIfCredentialFileExists()){
          $calendars =    $googleApi->calendarList();
            \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
            \Yii::$app->response->data = $calendars;
        }else{
            return $this->redirect(['auth']);
        }
    }

}


]]>
0
[extension] olegsoft/first-or-create Fri, 15 Jun 2018 16:46:17 +0000 https://www.yiiframework.com/extension/olegsoft/first-or-create https://www.yiiframework.com/extension/olegsoft/first-or-create olegtmb olegtmb

Trait For Yii2 ActiveRecord

  1. The idea is borrowed from Laravel framework.
  2. Installation
  3. Inserting into the ActiveRecord class
  4. Example of use

The idea is borrowed from Laravel framework.

Installation

The preferred way to install this extension is through composer.

php composer.phar require --prefer-dist olegsoft/first-or-create "dev-master"

Inserting into the ActiveRecord class

use olegsoft\firstOrCreate\FirstOrCreate;

class ModelTable extends \yii\db\ActiveRecord
{
    use FirstOrCreate;
    ...

Example of use

use app\models\ModelTable;
    ...

    //public static function firstOrNew($attributes, $values = [])
    $model = ModelTable::firstOrNew(['id' => 50]);
    $model = ModelTable::firstOrNew(['id' => 50], ['sort' => 10]);
    //Returns a single of the ActiveRecord model instance that matches the values of the $attribute array values 
    //or returns a new instance of the ActiveRecord model 
    //with properties corresponding to the values of the $attributes array + values of the $values array
       
    //public static function firstOrCreate($attributes, $values = [])
    $model = ModelTable::firstOrCreate(['id' => 50]);
    $model = ModelTable::firstOrCreate(['id' => 50], ['sort' => 10]);
    //Returns a single of the ActiveRecord model instance that matches the values of the $attribute array values 
    //or returns a new instance of the ActiveRecord model 
    //with properties corresponding to the values of the $attributes array + values of the $values array and save it
    
    //public static function updateOrCreate($attributes, $values = [])
    $model = ModelTable::updateOrCreate(['id' => 50]);
    $model = ModelTable::updateOrCreate(['id' => 50], ['sort' => 10]);
    //Finds the model from the passed attributes,
    //if the model is found, then assign the values of the $values and save it
    //if the model is not found, then create it with the values $attributes + $value and save it

    //public static function firstOrFail($attributes)
    $model = ModelTable::firstOrFail(['id' => 50]);
    //Return the model with the passed attributes, if the model is not found, then the HTTP 404 exception will be thrown

    //public static function findOrFail($attributes)
    $models = ModelTable::findOrFail(['id' => 50]);
    //Returns array of models by the passed attributes, if no model is found, then the HTTP 404 exception will be thrown
    
...
]]>
0
[extension] netesy/yii2-bulksms Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/netesy/yii2-bulksms https://www.yiiframework.com/extension/netesy/yii2-bulksms netesy netesy

A Yii2 extension to handle sending messages for most Nigerian bulksms http api connections

  1. Installation
  2. Supported websites
  3. Usage

A Yii2 extension to handle sending messages for most Nigerian bulksms http api connections

Installation

The preferred way to install this extension is through composer.

Either run

php composer require netesy/yii2-bulksms

or add

"netesy/yii2-bulksms": "*"

to the require section of your composer.json file.

Supported websites

NigerianBulkSMS

BetaSMS

Usage

Once the extension is installed, simply use it in your code by :

first add to config.php `php <?php 'components' => [

'bulksms' => [
      'class' => 'netesy\bulksms\BulkSms',
      'username' => 'xxxxxxxx',
      'password' => 'xxxxxxxx',
      'sender' => 'sender number',
      'url' => 'the api address',
      ],

] ?> `

Once the extension is installed, simply use it in your code by : to send a message `php <?php

Yii::$app->bulksms->sendMessage([
'number' => $number,
'message' => 'message',
  ]);

?> to send a callphp <?php

Yii::$app->bulksms->sendCall([
'number' => $number,
'message' => 'message',
  ]);

?> `

to get your account balance

<?php 
	Yii::$app->bulksms->getBalance();
 ?>
]]>
0
[extension] faboslav/yii2-material-tabs Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/faboslav/yii2-material-tabs https://www.yiiframework.com/extension/faboslav/yii2-material-tabs Faboslav Faboslav
  1. Installation
  2. Preview
  3. Usage
  4. Licence

Installation

The preferred way to install this extension is through composer.

Either run

$ php composer.phar require faboslav/yii2-material-tabs "dev-master"

or add

"faboslav/yii2-material-tabs": "dev-master"

to the `require` section of your composer.json file.

Preview

MaterialTabsPreview

Usage

MaterialNavBar
use faboslav\materialtabs\MaterialTabs

echo MaterialTabs::widget([
    'items' => [
        [
            'label' => '<i class="material-icons">home</i>',
            'content' => 'Tab one content.'
        ],
        [
            'label' => 'Tab two',
            'content' => 'Tab two content<br><br>Text<br><br>Text',
        ],
        [
            'label' => 'Tab three',
            'content' => 'Tab three content<br>Text<br>Text',
            'active' => true
        ],
        [
            'icon' => '<i class="material-icons">people</i>',
            'label' => 'Tab four',
            'content' => 'Tab four content<br><br>Text<br>Text'
        ],
        [
            'label' => 'Tab five',
            'content' => 'Tab five content<br>Text'
        ],
    ]
]);

Licence

The MIT License (MIT)

]]>
0
[extension] devanych/yii2-cart Thu, 07 Jun 2018 19:28:43 +0000 https://www.yiiframework.com/extension/devanych/yii2-cart https://www.yiiframework.com/extension/devanych/yii2-cart devanych devanych

Yii2 shopping cart

  1. Installation
  2. Configuration
  3. Usage
  4. Useful links

This extension adds shopping cart for Yii framework 2.0

Installation

The preferred way to install this extension is through Composer

Either run

php composer.phar require devanych/yii2-cart "*"

or add

devanych/yii2-cart: "*"

to the require section of your composer.json file.

Configuration

Configure the cart component (default values are shown):

return [
    //...
    'components' => [
        //...
        'cart' => [
            'class' => 'devanych\cart\Cart',
            'storageClass' => 'devanych\cart\storage\SessionStorage',
            'calculatorClass' => 'devanych\cart\calculators\SimpleCalculator',
            'params' => [
                'key' => 'cart',
                'expire' => 604800,
                'productClass' => 'app\model\Product',
                'productFieldId' => 'id',
                'productFieldPrice' => 'price',
            ],
        ],
    ]
    //...
];

In addition to devanych\cart\storage\SessionStorage, there is also devanych\cart\storage\CookieStorage and devanych\cart\storage\DbSessionStorage. It is possible to create your own storage, you need to implement the interface devanych\cart\storage\StorageInterface.

DbSessionStorage uses SessionStorage for unauthorized users and database for authorized.

If you use the devanych\cart\storage\DbSessionStorage as storageClass then you need to apply the following migration:

php yii migrate --migrationPath=@vendor/devanych/yii2-cart/migrations

devanych\cart\calculators\SimpleCalculator produces the usual calculation of the total cost and total quantity of items in the cart. If you need to make a calculation with discounts or something else, you can create your own calculator by implementing the interface devanych\cart\calculators\CalculatorInterface.

Setting up the params array:

  • key - For Session and Cookie.

  • expire - Cookie life time.

  • productClass - Product class is an ActiveRecord model.

  • productFieldId - Name of the product model id field.

  • productFieldPrice - Name of the product model price field.

Usage

You can get the shopping cart component anywhere in the app using Yii::$app->cart.

Using cart:

// Product is an AR model
$product = Product::findOne(1);

// Get component of the cart
$cart = \Yii::$app->cart;

// Add an item to the cart
$cart->add($product, $quantity);

// Adding item quantity in the cart
$cart->plus($product->id, $quantity);

// Change item quantity in the cart
$cart->change($product->id, $quantity);

// Removes an items from the cart
$cart->remove($product->id);

// Removes all items from the cart
$cart->clear();

// Get all items from the cart
$cart->getItems();

// Get an item from the cart
$cart->getItem($product->id);

// Get ids array all items from the cart
$cart->getItemIds();

// Get total cost all items from the cart
$cart->getTotalCost();

// Get total count all items from the cart
$cart->getTotalCount();

Using cart items:

// Product is an AR model
$product = Product::findOne(1);

// Get component of the cart
$cart = \Yii::$app->cart;

// Get an item from the cart
$item = $cart->getItem($product->id);

// Get the id of the item
$item->getId();

// Get the price of the item
$item->getPrice();

// Get the product, AR model
$item->getProduct();

// Get the cost of the item
$item->getCost();

// Get the quantity of the item
$item->getQuantity();

// Set the quantity of the item
$item->setQuantity($quantity);

By using method getProduct(), you have access to all the properties and methods of the product.

$product = $item->getProduct();

echo $product->name;

Useful links

Article with a detailed description in Russian language: https://zyubin.ru/frameworks/yii/rasshirenie-korzina-dlya-yii2.html

]]>
0
[extension] gevman/yii2-router Thu, 19 Jul 2018 21:31:25 +0000 https://www.yiiframework.com/extension/gevman/yii2-router https://www.yiiframework.com/extension/gevman/yii2-router gevorgmansuryan gevorgmansuryan ]]> 0 [news] Queue extension 2.1.0 released Wed, 23 May 2018 21:35:19 +0000 https://www.yiiframework.com/news/176/queue-extension-2-1-0-released https://www.yiiframework.com/news/176/queue-extension-2-1-0-released samdark samdark

We are very pleased to announce the release of Queue extension version 2.1.0.

Additionally to fixing bugs, the version brings two major enhancements on board. First, there is now Amazon SQS queue support.

Second, cli\Queue:EVENT_WORKER_LOOP worker loop event was added. It is called on each iteration between requests to queue.

Other than that, there are slightly updated documentation and new Japanese translation.

Full changelog is available at GitHub.

]]>
0
[wiki] pjax gridview delete button issue Fri, 11 May 2018 04:06:08 +0000 https://www.yiiframework.com/wiki/867/pjax-gridview-delete-button-issue https://www.yiiframework.com/wiki/867/pjax-gridview-delete-button-issue hehbhehb hehbhehb

Normally, after clicking the delete button in gridview, the record will be deleted and the page will refresh, but the page number in query string is lost. This is not always the case we expect.

How to refresh current page with pjax after deleting the record? It seems there is no very simple solution.

1.Controller file

    public function actionDelete($id)
    {
        $this->findModel($id)->delete();
        if (Yii::$app->request->isAjax) {
            Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
            return ['success' => true];
        }
        return $this->redirect(['index']);
    }

2.index.php(view file)

<?php
    $this->registerJs("
        $(document).on('ready pjax:success', function() {
            $('.pjax-delete-link').on('click', function(e) {
                e.preventDefault();
                var deleteUrl = $(this).attr('delete-url');
                var pjaxContainer = $(this).attr('pjax-container');
                var result = confirm('Delete this item, are you sure?');                                
                if(result) {
                    $.ajax({
                        url: deleteUrl,
                        type: 'post',
                        error: function(xhr, status, error) {
                            alert('There was an error with your request.' + xhr.responseText);
                        }
                    }).done(function(data) {
                        $.pjax.reload('#' + $.trim(pjaxContainer), {timeout: 3000});
                    });
                }
            });

        });
    ");
?>

<?php Pjax::begin(['id' => 'my_pjax']); ?>
    <div class="shop-index">
        <?= GridView::widget([
            'dataProvider' => $dataProvider,
            'filterModel' => $searchModel,
            'columns' => [
                'id',
                [
                    'class' => 'yii\grid\ActionColumn',
                    'buttons' => [
                        'update' => function ($url, $model) {
                            return Html::a('<span class="glyphicon glyphicon-pencil"></span>', $url, [
                                'class' => 'pjax-update-link',
                                'title' => Yii::t('yii', 'Update'),
                            ]);
                        },
                        'delete' => function ($url, $model) {
                            return Html::a('<span class="glyphicon glyphicon-trash"></span>', false, [
                                'class' => 'pjax-delete-link',
                                'delete-url' => $url,
                                'pjax-container' => 'my_pjax',
                                'title' => Yii::t('yii', 'Delete')
                            ]);
                        }
                    ],
                ],
            ],
        ]); ?>
    </div>
<?php Pjax::end(); ?>

]]>
0
[news] Gii extension 2.0.7 released Wed, 02 May 2018 22:09:25 +0000 https://www.yiiframework.com/news/175/gii-extension-2-0-7-released https://www.yiiframework.com/news/175/gii-extension-2-0-7-released samdark samdark

We are very pleased to announce the release of Gii extension version 2.0.7. The release corrects Gii behavior adapting it to changes introduced in version 2.0.15 of the framework. Additionally there are fixes in model and CRUD generators.

]]>
0
[news] Swiftmailer extension 2.1.1 released Tue, 24 Apr 2018 23:26:51 +0000 https://www.yiiframework.com/news/174/swiftmailer-extension-2-1-1-released https://www.yiiframework.com/news/174/swiftmailer-extension-2-1-1-released samdark samdark

We are very pleased to announce the release of Swiftmailer extension version 2.1.1 that fixes yii\swiftmailer\Mailer::setTransport had no effect after sending of first message.

]]>
0
[news] Smarty extension 2.0.7 released Tue, 24 Apr 2018 23:11:22 +0000 https://www.yiiframework.com/news/173/smarty-extension-2-0-7-released https://www.yiiframework.com/news/173/smarty-extension-2-0-7-released samdark samdark

We are very pleased to announce the release of Smarty extension version 2.0.7 that fixes widget registration and rendering code generation inside subtemplates and adds an ability to use SmartyBC class.

]]>
0
[wiki] Configuring PhpStorm IDE for Yii 2 Fri, 27 Apr 2018 13:08:08 +0000 https://www.yiiframework.com/wiki/865/configuring-phpstorm-ide-for-yii-2 https://www.yiiframework.com/wiki/865/configuring-phpstorm-ide-for-yii-2 CeBe CeBe

There are a few settings and plugins that can enhance the development experience with Yii in PHPStorm or IntelliJ IDEA. This article explains how to get the most out of your IDE.

This arcticle is valid for Yii 2 and above, there is an older article for Yii 1.1.

Plugins

  • Yii2 Support adds many useful tools that improve working with Yii. It makes working with class configuration, DI and views easier.

  • Yii2 Inspections is a very useful plugin that adds Yii specific code inspections to PHPStorm. It helps for example to manage @property annotations for getters and setters as well as translation messages.

  • Php Inspections (EA Extended) is not directly Yii related but has a lot of additional code inspections that help you write better code. There is also a paid version that has even more features, especially security related inspections.

Project Setup

  • Exclude runtime directories from code search. Debug toolbar stores a lot of stuff that clutters search results.

    runtime - right click - Mark Directory As - Excluded

  • Enable composer integration to tell PHPStorm to separate vendor files from project files.

    composer.json - right click - Composer - Init Composer ...

PHPUnit and Codeception

PHPStorm has integrations for PHPUnit as well as Codeception, so you can run your tests directly from the IDE.

Settings for that can be found at Run - Edit Configurations....

To add your Codeception tests, click the + button, select Codeception. Then enter the following details:

  • Name: "Codeception tests" - or whatever you want to name it
  • Test Scope: Defined in the Configuration file
  • Use alternative configuration file: "codeception.yml"
  • In case PHPStorm asks you to do it, configure a PHP Interpreter in PHPStorm settings
  • Configure Codeception binary as vendor/bin/codecept

You can now run your tests directly from PHPStorm.

For PHPUnit the steps are similar but Yii application templates do not provide PHPUnit tests by default so the options depend on your setup.

]]>
0
[wiki] How to login from different tables in Yii2 Thu, 05 Apr 2018 13:57:25 +0000 https://www.yiiframework.com/wiki/864/how-to-login-from-different-tables-in-yii2 https://www.yiiframework.com/wiki/864/how-to-login-from-different-tables-in-yii2 androidelp androidelp

The Problem: Yii2 utilizes by default UserIdentity configured in config/web.php for connection, this object appy one table to authentication ('identityClass' => 'app\painel\models\User'). How to authentication from diferent tables? Solution: Create instances in web.php to uses UserIdentify. eg:

$user = \Yii::$app->user;  
$school = \Yii::$app->school; 
$teacher = \Yii::$app->teacher;

My config/web.php

'user' => [
	'class'=>'yii\web\User',
	'identityClass' => 'app\models\User',
	'enableAutoLogin' => false,
	'authTimeout' => 60*30,
	'loginUrl' => ['dashboard/login'],
	'identityCookie' => [
		'name' => '_panelUser',
	]
],
'school'=>[
	'class'=>'yii\web\User',
	'identityClass' => 'app\models\SchoolUser',
	'enableAutoLogin' => false,
	'authTimeout' => 60*30,
	'loginUrl' => ['dashboard-school/login'],
	'identityCookie' => [
		'name' => '_panelSchool',
	]	
],
'teacher'=> [
	'class'=>'yii\web\User',
	'identityClass' => 'app\models\TeacherUser',
	'enableAutoLogin' => false,
	'authTimeout' => 60*30,
	'loginUrl' => ['dashboard-teacher/login'],
    'identityCookie' => [
		'name' => '_painelTeacher',
	]
],

Note that for each there is a identifyClass and one view login. Now, we need to create the models:

namespace app\models;
use Yii;
// My user
class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface
{
    public static function tableName()
    {
        return '{{%user}}';
    }
    // to continues....

Model scholl:


namespace app\models;
use Yii;
// My School
class SchoolUser' extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface
{
    public static function tableName()
    {
        return '{{%schoolUser}}';
    }
    // to continues
    

Model Teacher:


namespace app\models;
use Yii;
// My School
class TeacherUser'' extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface
{
    public static function tableName()
    {
        return '{{%teacher}}';
    }
    // to continues....

Now In my example I want to have controllers for each type of access, without generating conflicts between them:

In Behavior of the controller i have defined for dashboard-school, teacher and user, the user object representing the authentication status or the ID of the user application component.


	//behaviors of the school
public function behaviors()
{
	return [
        'access' => [
            'class' => AccessControl::className(),
            'user'=>'school', // this user object defined in web.php
            'rules' => [
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
                [
                    'allow' => true,
                    'actions' => ['login'],                    
 'roles' => ['?'],

                ],
            ],
        ]
    ];
}

To use login:

//school
\Yii::$app->scholl->login($model, $this->rememberMe ? 3600*24*30 : 0);

//teacher
\Yii::$app->teacher->login($model, $this->rememberMe ? 3600*24*30 : 0);

For restrict access in views:

<?php if (!\Yii::$app->scholl->isGuest):?>
<h1>My scholl Name: <?=\Yii::$app->scholl->identity->name?>
<?php endif;?>

<?php if (!\Yii::$app->teacher->isGuest):?>
<h1>Teacher Name: <?=\Yii::$app->teacher->identity->name?>
<?php endif;?>

Always use the specific instance of the user you want to work with.

Criticism, suggestions and improvements, use the comments

]]>
0
[news] MongoDB extension 2.1.7 released Tue, 24 Apr 2018 23:09:22 +0000 https://www.yiiframework.com/news/172/mongodb-extension-2-1-7-released https://www.yiiframework.com/news/172/mongodb-extension-2-1-7-released samdark samdark

We are very pleased to announce the release of MongoDB extension version 2.1.7 that fixes Yii 2.0.14+ incompatibility and enhances Session component error reporting.

]]>
0
[news] Shell extension version 2.0.1 released Mon, 26 Mar 2018 14:53:24 +0000 https://www.yiiframework.com/news/171/shell-extension-version-2-0-1-released https://www.yiiframework.com/news/171/shell-extension-version-2-0-1-released samdark samdark

We are very pleased to announce the release of Shell extension version 2.0.1 which updates psy/psysh dependency to 0.8.x versions.

]]>
0
[wiki] Use non Gmail/Gsuite on Gcloud projects Sun, 15 Jul 2018 14:00:50 +0000 https://www.yiiframework.com/wiki/863/use-non-gmailgsuite-on-gcloud-projects https://www.yiiframework.com/wiki/863/use-non-gmailgsuite-on-gcloud-projects gogl92 gogl92

Small companies and startups use cheap email services or even Cpanel's mail services which are less secure and compete directly with bigger email providers like Microsoft with Outlook and Google with Gmail. This creates a problem when you try to use their services to send/receive emails from this cheap services. google-cloud-platform.png

Google says this: Google Compute Engine does not allow outbound connections on ports 25, 465, and 587. By default, these outbound SMTP ports are blocked because of the large amount of abuse these ports are susceptible to. In addition, having a trusted third-party provider such as SendGrid, Mailgun, or Mailjet relieves Compute Engine and you from maintaining IP reputation with your receivers.

Some time ago I had a project that requieres this, send emails using a cpanel mail services but we have Google Cloud services so when the client send me the credentials to put it in production the app crashes in a critical time, client will not pay to use Gsuite and I have all the stuff ready for production and configured in Google Cloud, so I found a solution.

  • Make sure you have swiftmail extension installed (it also comes with the basic and advance template)
  1. First get a Gmail or Gsuite account to use it as a bridge between emails. The name doesn't matter it will never be seen by final users. let's say mail_service54@gmail.com or use a Gsuite custom email. It is also important that you have full priviledges to this email as you will need it in the next step.
  2. Enable less secure apps to your email. [https://support.google.com/accounts/answer/6010255?hl=en](Official Docs here)
  3. Now configure the swiftmailer extension to send emails with your account. I use this config for gmail/gsuite accounts:
    'mailer' => [
             'class' => 'yii\swiftmailer\Mailer',
             'transport' => [
                 'class' => 'Swift_SmtpTransport',
                 'host' => 'smtp.gmail.com',
                 'username' => 'yourmail@gmail.com',
                 'password' => 'your password',
                 'port' => '587',
                 'encryption' => 'tls',
             ],
         ],
    
  4. Test that you can send an email so we can get sure the past configuration works well.
  5. After you can send an email, login into your account on the web and go to settings > Accounts and Import > Send mail as
  6. Do the import process of the other service/cpanel email, usually they will send you a link/code to the other email and you will have to confirm it.
  7. Now you can from your gmail account send mails as some other mail.
  8. Do this in your Yii code:
    Yii::$app->mailer->compose()
     ->setFrom('from@cpanel-mail.com')
     ->setTo('to@domain.com')
     ->setSubject('Message subject')
     ->setTextBody('Plain text content')
     ->setHtmlBody('<b>HTML content</b>')
     ->send();
    

    And that's it!

This is the first post of many about using Yii/Open Source in business and enterprise level becuase Open source != not cost.

]]>
0
[news] Finally releasing the new Yiiframework.com website Mon, 26 Mar 2018 14:51:57 +0000 https://www.yiiframework.com/news/169/finally-releasing-the-new-yiiframework-com-website https://www.yiiframework.com/news/169/finally-releasing-the-new-yiiframework-com-website CeBe CeBe

We are very happy to announce that the new yiiframework.com website is finally ready for deployment.

A huge thanks to Сергей Хильков (eshill) for his design work, to Jacob Moen and Nikola Trifunović for the countless hours spent on tweaking the frontend code and doing pages markup. Thanks to prodex, Robert Korulczyk and other contributors for fixes and additions.

There is a forum topic for discussion on this announcement.

Content

The new website will keep most of the content that is currently available online. We tried to keep existing content in the same places, so URLs should be the same as before. If you find that content is missing that was available before, please report to website project issues.

You can have a look at the new site on https://new.yiiframework.com/. Please note that this is just a preview. All content there will be re-imported destroying all the changes made when we'll deploy production version. Be careful with the forum however as it is real production one proxied to the new site :)

The new website puts more focus on the documentation, making Guide and API docs the first items in the navigation. You can now also directly search for API entries from the main navigation search field. You can search for class names and also method and property names, e.g. ActiveRecord.save() or just .save() or ::save().

Wiki and Extensions are available as before. Extensions now integrate with packagist, so if your extension is listed on packagist.org you no longer have to maintain two different places, the content is automatically synced with packagist if you enter the packagist URL in the extension properties.

The community section still has the old forum, which will continue to operate as before for now. We might replace the forum with a better solution in the future. Also badges and ranking functionality has been ported from the old website.

Other information about Yii is now grouped under the "More" point in the navigation.

User accounts

We have imported all user accounts from the old website. You should be able to log in with your user name and password as before. If it does not work, there is a password reset option. In case you lost access to your account, we'll be there to help, please report to website project issues or write an email to admin@yiiframework.com.

You can now log in with github. To connect your existing login with your github account, log in regularly first, then go to your profile page (click on your user name on the top right) and authorize github. You won't need to type password again.

Feedback

If you have feedback about the new website, or you found a bug, please report in the Github issue tracker.

Roadmap

We are going to switch to the new website on March 23, 2018 in the time frame 8:00 to 12:00 UTC. During the switch, you will not be able to write comments, wikis, forum entries etc. Also the documentation may not be available. You can use http://stuff.cebe.cc/yii2docs/ to view the documentation.

We will be avilable in the Slack chat and on IRC #yii on freenode, so if you need help, get there.

]]>
0
[news] Releasing Yii 2.0.15 and database extensions with security fixes Mon, 09 Apr 2018 21:18:03 +0000 https://www.yiiframework.com/news/168/releasing-yii-2-0-15-and-database-extensions-with-security-fixes https://www.yiiframework.com/news/168/releasing-yii-2-0-15-and-database-extensions-with-security-fixes CeBe CeBe

Today we are releasing several versions for Yii 2.0.x and official extensions to fix a security issue.

The problem addressed in these patches exists in ActiveRecord shortcut methods findOne() and findAll(), which may allow SQL injection if input is not prepared properly. We consider this as a security issue in Yii because the documentation for these methods did not contain an explicit warning that there are cases when passing unfiltered user input might be dangerous. Thanks to analitic1983 for making us aware of the issue.

The nature of this issue does not solely exists in the Yii Framework but depends on how an application uses Yii. We have changed Yii to be more robust against the worst impact of the problem (SQL injection), but applications may still be vulnerable and changes to application code are necessary in some cases. As a safety measure, findOne() and findAll() are now limited to filter on columns that are AR properties only. In the following we will explain the problem in more detail and show which application code is affected and what needs to be adjusted on upgrade.

For discussion on this issue, there is a forum topic.

Summary of Affected Classes, Methods and Composer Packages

  1. Not Affected Code
  2. Affected Code
  • yii\db\ActiveRecord::findOne() and yii\db\ActiveRecord::findAll() in yiisoft/yii2 referenced as CVE-2018-7269. Methods allow SQL injection if input is not prepared properly. Attackers could probably execute arbitrary SQL queries or circumvent access checking methods applied on query level.
  • yii\redis\ActiveRecord::findOne() and yii\redis\ActiveRecord::findAll() in yiisoft/yii2-redis referenced as CVE-2018-8073. Methods allow remote code execution in redis servers lua script environment. Attackers could probably manipulate data on the redis server.
  • yii\elasticsearch\ActiveRecord::findOne() and yii\elasticsearch\ActiveRecord::findAll() in yiisoft/yii2-elasticsearch referenced as CVE-2018-8074. Methods may allow injecting different search condition than desired or cause an error response from the elasticsearch server.

Is my Application Affected?

  1. Not Affected Code
  2. Affected Code

This vulnerability affects all releases of the 2.0.x branch. It is fixed in Yii 2.0.15. For versions below 2.0.15, we have released two patch versions, 2.0.13.2 and 2.0.12.1, which apply the fix to 2.0.13.1 and 2.0.12 respectively. Users of 2.0.14, can upgrade to 2.0.15, there are no other changes made in this release.

Not Affected Code

The methods findOne() and findAll() accept a single argument, which can be scalar or array. If the calling code ensures that a scalar is passed or if client inputs cannot modify the array's structure, your application is not affected by this issue. The following code examples are not affected by this issue (examples shown for findOne() are valid also for findAll()):

// yii\web\Controller ensures that $id is scalar
public function actionView($id)
{
    $model = Post::findOne($id);
    // ...
}
// casting to (int) or (string) ensures no array can be injected (an exception will be thrown so this is not a good practise)
$model = Post::findOne((int) Yii::$app->request->get('id'));
// explicitly specifying the colum to search, passing a scalar or array here will always result in finding a single record
$model = Post::findOne(['id' => Yii::$app->request->get('id')]);

Affected Code

The following code however is vulnerable, an attacker could inject an array with an arbitrary condition and even exploit SQL injection:

$model = Post::findOne(Yii::$app->request->get('id'));

For the above example, the SQL injection part is fixed with the patches provided in this release, but an attacker may still be able to search records by different condition than a primary key search and violate your application business logic. So passing user input directly like this can cause problems and should be avoided.

How do I Upgrade?

  1. Not Affected Code
  2. Affected Code

If you are using Yii 2.0.14:

composer require "yiisoft/yii2":"~2.0.15.0"

If you are using Yii 2.0.13:

composer require "yiisoft/yii2":"~2.0.13.2"

If you are using Yii 2.0.12:

composer require "yiisoft/yii2":"~2.0.12.1"

If you are using yii2-redis extension:

composer require "yiisoft/yii2-redis":"~2.0.8"

If you are using yii2-elasticsearch extension:

composer require "yiisoft/yii2-elasticsearch":"~2.0.5"

Update: We have since released further patches to lower the impact of the BC break introduced by the security fix, so you get versions 2.0.15.1, 2.0.13.3 and 2.0.12.2 from the above.

Upgrading isn't Enough!

  1. Not Affected Code
  2. Affected Code

Upgrading Yii addresses the SQL injection but doesn't make findOne() and findAll() safe in general. Check all usages of findOne() and findAll() in your application. Also note, that where() and filterWhere() never escape column names, so if you need to pass a variable as a column name, make sure it is safe.

]]>
0
[news] Imagine extension version 2.1.1 released Thu, 22 Feb 2018 22:47:48 +0000 https://www.yiiframework.com/news/167/imagine-extension-version-2-1-1-released https://www.yiiframework.com/news/167/imagine-extension-version-2-1-1-released samdark samdark

We are very pleased to announce the release of Imagine extension version 2.1.1 which both fixes bugs and makes small enhancements.

This release updates 'Imagine' dependency to include versions 0.7.x.

See CHANGELOG for details.

]]>
0
[news] Faker extension version 2.0.4 released Mon, 19 Feb 2018 20:36:11 +0000 https://www.yiiframework.com/news/166/faker-extension-version-2-0-4-released https://www.yiiframework.com/news/166/faker-extension-version-2-0-4-released samdark samdark

We are very pleased to announce the release of Faker extension version 2.0.4 which both fixes bugs and makes small enhancements.

See CHANGELOG for details.

]]>
0
[news] Yii 2.0.14 is released Thu, 08 Mar 2018 23:11:09 +0000 https://www.yiiframework.com/news/165/yii-2-0-14-is-released https://www.yiiframework.com/news/165/yii-2-0-14-is-released SilverFire SilverFire
  1. Scalability and concurrency
  2. Validator enhancements
  3. Behaviors
  4. Databases and ActiveRecord
  5. Error handling
  6. Security
  7. PHP 7.2
  8. Widgets, forms and clientside
  9. Events
  10. APIs, serializers and filters
  11. Console
  12. Routing
  13. i18n
  14. Helpers
  15. DI container
  16. Project templates
  17. Preparing for 2.1

We are very pleased to announce the release of Yii Framework version 2.0.14. Please refer to the instructions at http://www.yiiframework.com/download/ to install or upgrade to this version.

Version 2.0.14 is a minor release of Yii 2.0 which contains more than a hundred enhancements and bug fixes including security fixes. It is also the last version of Yii 2.0 that contains enhancements. This means that we will focus on including new features into the 2.1.x branch and 2.0.x will only receive bug fixes from now on. We will make an announcement on the time frames for supporting different branches with the release of version 2.1.

There are minor changes that may affect your existing applications, so make sure to check the UPGRADE.md file.

Thanks to all Yii community members who contribute to the framework. We did it together!

You may follow the development progress of Yii 2 by starring or watching Yii 2.0 GitHub Project. There are many active Yii communities so if you need help or want to share your experience, feel free to join them.

Since there is Yii 2.1 in development now, make sure you have a version constraint in your composer.json, that does not allow it to be installed automatically on update, so when next major version of Yii is released, your project won't break by itself. A version constraint that does not include 2.1 is for example ~2.0.14, make sure you do not have >= or * in version constraints in composer.json.

Below we summarize some of the most important features/fixes included in this release. A complete list of changes can be found in the CHANGELOG.

Scalability and concurrency

While not important at early project stages, scalability and concurrency issues are major obstacles for business growth. In this release we have identified and fixed a concurrency issue when writing values and regenerating IDs in yii\web\DbSession and three issues that may appear in master-slave setups while using yii\web\DbSession, yii\validators\UniqueValidator and yii\validators\ExistValidator.

Validator enhancements

Additionally to what's mentioned in previous section, there are enhancements in built-in validators.

First, the ExistValidator is now able to check relations when its new targetRelation property is set. That basically means the following rules definition is now possible:

public function rules()
{
    return [
        [['customer_id'], 'exist', 'targetRelation' => 'customer'],
    ];
}

public function getCustomer()
{
    return $this->hasOne(Customer::class, ['id' => 'customer_id']);
}

Another enhancement is about FileValidator. It got a new property called minFiles to specify the minimum number of files a user must upload.

Behaviors

yii\behaviors\BlameableBehavior got a defaultValue property that is used in case user ID could not be determined. That is often the case when Active Record model is used within console application.

New yii\behaviors\AttributeTypecastBehavior property typecastAfterSave could be set to true to make values typecasted after model is saved. That makes attribute types consistent if they're casted when saved to database.

New yii\behaviors\CacheableWidgetBehavior was added. It automatically caches widget contents according to duration and dependencies specified and could be added to a widget like the following:

use yii\behaviors\CacheableWidgetBehavior;

public function behaviors()
{
  return [
      [
          'class' => CacheableWidgetBehavior::className(),
          'cacheDuration' => 0,
          'cacheDependency' => [
              'class' => 'yii\caching\DbDependency',
              'sql' => 'SELECT MAX(updated_at) FROM posts',
          ],
      ],
  ];
}

Databases and ActiveRecord

This release adds lots of great things related to databases and ActiveRecord that were worked by Dmitry Naumenko, Sergey Makinen, Robert Korulczyk, Nikolay Oleynikov and other community members.

Custom data types and object conditions

Custom data types support was implemented. Added JSON support for MySQL and PostgreSQL and arrays support for PostgreSQL. In order to do that, Query Builder internals were refactored significantly and now support object format for conditions:

$query->andWhere(new OrCondition([
    new InCondition('type', 'in', $types),
    ['like', 'name', '%good%'],
    'disabled=false',
]));

There are two good things about it. First, it's easier to support existing conditions and add new ones for Yii team. Additionally to conditions for JSON and arrays, it already resulted in a new BetweenColumnsCondition. There could be more added in Yii 2.1. Second, it's convenient to add custom conditions now.

Query Builder flexibility

Query Builder flexibility was improved overall. It is now possible to pass yii\db\Query anywhere, where yii\db\Expression was supported. For example, it is now possible to use it like the following:

$subquery = (new Query)
    ->select([new Expression(1)])
    ->from('tree')
    ->where(['parent_id' => 1, 'id' => new Expression('tree.parent_id']));

(new Query())
    ->from('tree')
    ->where(['or', 'parent_id = 1', $subquery])
Upserts

Another big thing is upserts for all databases Yii database layer supports. Upsert is an atomic operation that inserts rows into a database table if they do not already exist (matching unique constraints), or update them if they do:

Yii::$app->db->createCommand()->upsert('pages', [
    'name' => 'Front page',
    'url' => 'http://example.com/', // URL is unique
    'visits' => 0,
], [
    'visits' => new \yii\db\Expression('visits + 1'),
], $params)->execute();

Will either insert a new page record or increment its visit counter atomically.

Schema builder and migrations

Schema builder now supports tiny integer and JSON so you can use the following in migrations:

$this->createTable('post', [
    'id' => $this->primaryKey(),
    'text' => $this->text(),
    'title' => $this->string()->notNull(),
    'attributes' => $this->json(),
    'status' => $this->tinyInteger(),
]);

Another enhancement about migrations is the ability to create and drop database views:

$this->createView(
    'top_10_posts',
    (new \yii\db\Query())
        ->from('post')
        ->orderBy(['rating' => SORT_DESC])
        ->limit(10)
);

$this->dropView('top_10_posts');
New query caching syntax

It was possible before to wrap DB calls with connection's cache method. Now there are handy shortcuts:

// at query level
(new Query())->cache(7200)->all();

// at AR level
User::find()->cache(7200)->all();
Active Record relations

Active Record now resets related models after corresponding attribute updates:

$item = Item::findOne(1);
echo $item->category_id; // 1
echo $item->category->name; // weapons

$item->category_id = 2;
echo $item->category->name; // toys

Error handling

Log targets now throw exception in case log can't be exported properly. Previously they were failing silently.

Another case where Yii is now throwing yii\web\HeadersAlreadySentException exception instead of being silent if headers were already sent before (thus, it's not possible to send more).

It is now possible to configure Yii error handler via setting $traceLine property to generate links in the exception code so these could be opened directly in IDE. Configuration is similar to debug toolbar:

'components' => [
    // ...
    'errorHandler' => [
        'errorAction' => 'site/error',
        'traceLine' => '<a href="ide://open?url={file}&line={line}">{html}</a>',
    ],
],

Using yii\web\ErrorAction::$layout property you can set layout from error action config conveniently:

class SiteController extends Controller
{
    // ...
    /**
     * @inheritdoc
     */
    public function actions()
    {
        return [
            'error' => [
                'class' => 'yii\web\ErrorAction',
                'layout' => 'error', // <-- HERE
        ],
    ];
}

Security

There are two vulnerabilities discovered and fixed in this release:

  • CVE-2018-6009. The switchIdentity() function in web/User.php did not regenerate the CSRF token upon a change of identity.
  • CVE-2018-6010. Remote attackers could obtain potentially sensitive information from exception messages printed by the error handler in non-debug mode.

PHP 7.2

This release brings full PHP 7.2 compatibility. We have adjusted yii\filters\HttpCache, FileHelper::getExtensionsByMimeType() and yii\web\Session to work well with all PHP versions we support.

Widgets, forms and clientside

Markup generated for <script> tag doesn't have type attribute anymore. Additionally to better looking, it makes HTML5 markup validator happy.

In form active fields (for both Active Form and Html helper) you can now automatically include placeholder that matches field's attribute:

<?=  Html::activeTextInput($post, 'title', ['placeholder' => true]) ?>

Another thing added to ActiveForm is an ability to choose which HTML element receives validation state classes:

<?php $form = ActiveForm::begin([
    'validationStateOn' => ActiveForm::VALIDATION_STATE_ON_INPUT,
]) ?>

That possibly allows Yii bootstrap extension to adopt Bootstrap 4.

It's now possible to register JavaScript variables via PHP code:

class SiteController extends Controller
{
    public function actionIndex()
    {
        $this->view->registerJsVar('username', 'SilverFire');
        return $this->render('index');
    }
}

While it is widely used method of passing data from PHP to JavaScript, before using it consider HTML5 data attributes.

Events

Paul Klimov added wildcard matching to events so it's now possible to subscribe to multiple objects or class events that match the pattern. That is very useful for logging and audit. Brand new section in the guide is full of examples using the feature.

APIs, serializers and filters

When configuring JsonResponseFormatter you can now specify content type:

'components' => [
    'response' => [
        // ...
        'formatters' => [
            \yii\web\Response::FORMAT_JSON => [
                'class' => \yii\web\JsonResponseFormatter::className(),
                'contentType' => \yii\web\JsonResponseFormatter::CONTENT_TYPE_HAL_JSON,
            ],
        ],
    ],
]

Data filter can now handle lt,gt,lte and gte on yii\validators\DateValidator.

yii\base\ArrayableTrait::toArray() now allows recursive $fields and $expand. That means REST APIs queries expand could be specified now as extra1.extra2 and that would expand extra1 in the original data set and then extra2 in extra1 data set i.e. queries like http://localhost/comments?expand=post.author are possible.

In case you need to convert model validation errors into JSON you may use \yii\helpers\Json::errorSummary() now.

Custom authentication headers are now easier to set up thanks to added yii\filters\auth\HttpHeaderAuth.

Console

How many times you wished there was a built-in method to print model validation errors into console instead of doing foreach? Now there is one:

if (!$model->validate()) {
    echo "Model is not valid:\n";
    echo \yii\helpers\Console::errorSummary($model);
    return ExitCode::DATAERR;
}

bash and zsh command completion got better. Now it understands ./yii help.

When invoking a command options could now be specified as both camelCase and kebab-case i.e. --selfUpdate and --self-update. Moreover, in addition to --<option>=<value> console optios syntax, it's now possible to use --<option> <value> syntax.

Routing

Short verb syntax could now be used in URL rule groups:

'components' => [
    'urlManager' => [
        // ...
        'rules' => [
            new GroupUrlRule([
                'prefix' => 'file',
                'rules' => [
                    'POST document' => 'document/create',
                ],
            ]),
    ],
],

i18n

New yii\i18n\Locale component was added having getCurrencySymbol() method that is able to get currency symbol for a given locale.

Helpers

This release brings very interesting enhancements to Yii helpers.

yii\helpers\FileHelper got two new methods. findDirectories() returns the directories found under the specified directory and subdirectories. It is similar to existing findFiles() but works with directories. unlink() removes a file or symlink in a cross-platform way which proved to be tricky.

yii\helpers\StringHelper got a new matchWildcard() method that does the same as native fnmatch() but does it consistently among different OS. Native one proved to differ from system to system.

yii\helpers\IpHelper was added. It allows determining IP version by address, comparing address against a mask or range, and expanding IPv6. Usage is simple and convenient:

if (!IpHelper::inRange($ip, '192.168.1.0/24')) {
    // deny access
}

DI container

Container got an ability to reuse definitions as properties:

'container' => [
    'definitions' => [
        \console\models\TestService::class => [
            'class' => \console\models\TestService::class,
            'model' => Instance::of(\console\models\TestModel::class)
        ],
        \console\models\TestModel::class => [
            'class' => \console\models\TestModel::class,
            'property' => 20,
        ],
    ],
],

In the code above the model property of TestService will be set with an instance of TestModel class configured in the container.

Project templates

Additionally to minor adjustments basic project template got Docker and vagrant support.

Preparing for 2.1

Brandon Kelly proposed a very good idea to mark some methods and classes that were already removed in 2.1 as deprecated. That should make transition from 2.0 to 2.1 easier:

  • Deprecated yii\base\BaseObject::className() in favor of native PHP syntax ::class, which does not trigger autoloading (only works with PHP >=5.5).
  • Deprecated XCache and Zend data cache support as caching backends.
  • Deprecated yii\BaseYii::powered() method.
  • Added yii\base\InvalidArgumentException and deprecated yii\base\InvalidParamException.
  • Added yii\BaseYii::debug() and deprecated yii\BaseYii::trace().

Code using these methods would work as usual except that IDEs will mark it deprecated.

]]>
0
[news] Bootstrap extension version 2.0.8 released Fri, 16 Feb 2018 18:37:06 +0000 https://www.yiiframework.com/news/164/bootstrap-extension-version-2-0-8-released https://www.yiiframework.com/news/164/bootstrap-extension-version-2-0-8-released samdark samdark

We are very pleased to announce the release of Bootstrap extension version 2.0.8 which both fixes bugs and makes small enhancements.

See CHANGELOG for details.

]]>
0
[news] MongoDB extension 2.1.5 released Tue, 13 Feb 2018 16:05:45 +0000 https://www.yiiframework.com/news/163/mongodb-extension-2-1-5-released https://www.yiiframework.com/news/163/mongodb-extension-2-1-5-released samdark samdark

We are very pleased to announce the release of MongoDB extension version 2.1.6 which brings two bug fixes:

  • Fixed yii\mongodb\Command::aggregate() without 'cursor' option produces error on MongoDB Server 3.6
  • Fixed yii\mongodb\Collection::dropIndex() unable to drop index specified with sort via index plugin

See CHANGELOG for details.

]]>
0
[news] Sphinx extension 2.0.10 released Tue, 13 Feb 2018 16:05:52 +0000 https://www.yiiframework.com/news/162/sphinx-extension-2-0-10-released https://www.yiiframework.com/news/162/sphinx-extension-2-0-10-released samdark samdark

We are very pleased to announce the release of Sphinx extension version 2.0.10 which brings 4 enhancements and bug fixes:

  • Fixed yii\sphinx\Schema::findColumns() unable to merge field and attribute columns with same name
  • Fixed yii\sphinx\QueryBuilder::buildInCondition() incompatibility with PHP 7.2
  • yii\sphinx\QueryBuilder::callSnippets() now automatically casts snippet source to string
  • yii\sphinx\QueryBuilder now supports Traversable objects for use in in conditions

See CHANGELOG for details.

]]>
0
[news] Http Client extension 2.0.6 released Tue, 13 Feb 2018 16:06:00 +0000 https://www.yiiframework.com/news/161/http-client-extension-2-0-6-released https://www.yiiframework.com/news/161/http-client-extension-2-0-6-released samdark samdark

We are very pleased to announce the release of HTTP client extension version 2.0.6 which brings an enhancement and a bug fix:

  • Fixed Message::getHeaders() unable to parse HTTP status code in case reason phrase contains : character
  • Request::createFullUrl() now prevents appearance of multiple slashes while combining Client::$baseUrl and Request::$url

See CHANGELOG for details.

]]>
0
[news] Auth Client extension 2.1.5 released Wed, 07 Feb 2018 21:19:53 +0000 https://www.yiiframework.com/news/160/auth-client-extension-2-1-5-released https://www.yiiframework.com/news/160/auth-client-extension-2-1-5-released samdark samdark

We are very pleased to announce the release of Auth Client extension version 2.1.5 which brings 3 enhancements and bug fixes:

  • Updated endpoint URLs for LinkedIn.
  • AuthAction refactored to use yii\web\Application::$request for request data access.
  • Added yii\authclient\AuthAction::$cancelCallback allowing custom handling for authentication cancellation.

See the CHANGELOG for details.

]]>
0
[news] Portland Yii Framework Programmers Meetup Tue, 09 Jan 2018 07:44:01 +0000 https://www.yiiframework.com/news/159/portland-yii-framework-programmers-meetup https://www.yiiframework.com/news/159/portland-yii-framework-programmers-meetup samdark samdark

Jeff Reifman started Yii meetup in Portland, Oregon.

First one will take place Tuesday, January 16, 2018 6:30 PM to 8:30 PM at Palio 1996 SE Ladd Av.

If you're nearby, join it. Here's meetup page at meetup.com.

]]>
0
[news] Queue Extension 2.0.2 released Tue, 26 Dec 2017 17:34:43 +0000 https://www.yiiframework.com/news/158/queue-extension-2-0-2-released https://www.yiiframework.com/news/158/queue-extension-2-0-2-released samdark samdark

We have released version 2.0.2 of the Queue extension. This version is fixing bugs as well as adding some enhancements.

New AMQP Interop driver added. It allows you to seamlessly use many drivers queue interop project supports.

There are new events: cli\Queue::EVENT_WORKER_START and cli\Queue::EVENT_WORKER_STOP. These allow you to add handlers to worker start and stop.

It's now possible to redefine exit code that is useful for connecting workers with Supervisord or Systemd.

LoopInterface and its SignalLoop implementation were added in order to handle posix-signals. Out of the box SignalLoop provides an ability to exit the loop using a signal. Also it supports querying delays. Exit, pause and resume signals are configurable as well.

New events and LoopInterface are supported by all CLI drivers except AMQP and AMQP Interop.

]]>
0
[wiki] Yii2 RESTful API with OAuth 2.0 Sun, 25 Mar 2018 02:00:49 +0000 https://www.yiiframework.com/wiki/862/yii2-restful-api-with-oauth-2-0 https://www.yiiframework.com/wiki/862/yii2-restful-api-with-oauth-2-0 sirin_ibin sirin_ibin

https://cdn.pbrd.co/images/GMN5ROs.jpg

Overview

This article is for the one’s who is already working with PHP/Yii2 or who wants to quick start developing a RESTful API using Yii2 framework with

  1. OAuth 2.0 authentication
  2. A developer dashboard
  3. API documentation template

Here I’m sharing the Live demo and Source code of a RESTful API with OAuth2 authentication/security developed using Yii2 framework You can use this if you want to quick start developing your own custom RESTful API by skipping 95% of your scratch works. Hopefully this will save lot of your time as this API includes all the basic stuffs you need to get started.

Developer Dashboard

This API also includes a developer dashboard with the API documentation which is developed in Yii2 framework. This will be useful to manage your developers access to the API documentation.

Why Yii2?

Yii2

It's Fast, It’s Secure and Professional!. Yii comes with rich features: MVC, DAO/ActiveRecord, I18N/L10N, caching, authentication and role-based access control, scaffolding, testing, etc. It can reduce your development time significantly.

What is a RESTful API?

REST is an architectural style for building APIs. It stands for “Representational State Transfer”. It means when we build an API, we build it in a way that HTTP methods and URIs mean something, and the API has to respond in a way that’s expected.

Something about OAuth 2.0

The OAuth 2.0 is an authorization framework which enables a third-party application to obtain limited access to an HTTP service.

DEMO

http://yii2-rest.dockerboxes.us

Login: developer/developer

Source Code

https://github.com/sirinibin/Yii2-RESTful-API-with-OAuth2

Official Documentation

Documentation for this RESTful API can be found on the Yii 2.0 RESTful API with OAuth 2.0 Documentation. Security Vulnerabilities

If you discover a security vulnerability within this API, please send an e-mail to Sirin k at sirin@nintriva.com. All security vulnerabilities will be promptly addressed.

Installation instructions

https://github.com/sirinibin/Yii2-RESTful-API-with-OAuth2

Sirin K

]]>
0
[wiki] How to get SEO friendly URL using Model and new getUrl() function Thu, 21 Sep 2017 04:25:33 +0000 https://www.yiiframework.com/wiki/861/how-to-get-seo-friendly-url-using-model-and-new-geturl-function https://www.yiiframework.com/wiki/861/how-to-get-seo-friendly-url-using-model-and-new-geturl-function shivam4u shivam4u

We all need SEO friendly URLs for our projects. its not always good to call route with params so we can generalise it for all models using a common function.

Following the general convention of model and control sharing common name, we can use this code to get seo friendly URL.

public function getControllerID() {
		$modelClass = get_class ( $this );
		$pos = strrpos ( $modelClass, '\\' );
		$class = substr ( $modelClass, $pos + 1 );
		return Inflector::camel2id ( $class );
	}
	public function getUrl($action = 'view', $id = null) {
		$params = [ 
				$this->getControllerID () . '/' . $action 
		];
		if ($id != null)
			$params ['id'] = $id;
		else
			$params ['id'] = $this->id;
		// add the title parameter to the URL
		$params ['title'] = ( string ) $this;
		// absolute url
		return Yii::$app->getUrlManager ()->createAbsoluteUrl ( $params, true );
	}

In code code where ever you need to url to a model , you just call $model->url or $model->getUrl('view').

You may have to additionally update urlManager in config with rules for pretty url.

'<controller:[A-Za-z-]+>/<id:\d+>/<title>' => '<controller>/view',
								'<controller:[A-Za-z-]+>/<id:\d+>' => '<controller>/view',
								'<controller:post>/<id:\d+>/<title>' => 'blog/view',
								'<controller:[A-Za-z-]+>/<action:[A-Za-z-]+>/<id:\d+>/<title>' => '<controller>/<action>',
								'<controller:[A-Za-z-]+>/<action:[A-Za-z-]+>/<id:\d+>' => '<controller>/<action>',
	

you will get url like this.

http://localhost/link/650/need-a-professional-developer

]]>
0
[wiki] Yii2 Report Grid Mon, 26 Mar 2018 10:10:29 +0000 https://www.yiiframework.com/wiki/860/yii2-report-grid https://www.yiiframework.com/wiki/860/yii2-report-grid chrisb34 chrisb34

A Yii2 Gridview designed specifically for reporting

  1. Why is this significant
  2. Widget Setup
  3. Column Configuration

There are some very advanced grids in the Yii2 community, specifically Kartik's amazing gridview extensions but they all designed for interactive screen use.

ReportGrid is designed to provide report results to users, without filtering or sorting.

But more importantantly it has sub-totalling and report totalling built into the gridview itself.

Why is this significant

Because it enables you to use closures (anonymous functions) within the sub-total fields. For example, say we want to build a report on order items, with a break at order level. At the order level, we want to report something off the order model but the dataProvider is on the order-item level.

With ReportGrid, we can do this by using a closure on the sub-total to return the $model->order->some_relationship->some_value

Installation The preferred way to install this extension is through composer. Either run:

$ php composer.phar require chrisb34/reportgrid "@dev"

or add:

"chrisb34/yii2-report-grid": "@dev"

to the require section of your composer.json file. Then run:

php composer.phar update

to get the updated package on your application install.

Widget Setup

As with most Yii2 widgets, you control the using options on widget creation. This widget is based on the Yii2 gridview widget, so anything mentioned here is over and above the base options on the gridview widget

Note: that this widget does not support pagination. It actively switches pagination off in the dataProvider

  • controlBreak : boolean, turn on all this functionality. defaults to true. If set to false will make this widget behave like a notmal gridView

  • totalRowOptions : array, array list of options eg: [ 'class'=>'total-row']

  • totalsHeader : boolean, whether to repeat the table header row just before the report totals.

  • exportCSV : boolean, whether to include the 'Export to CSV' button

  • afterRow : closure, provides the ability to output an extra row after every model row. Closure call in the format function( $model, $key, $index)

  • pageSummary : closure, provides the ability to output an extra row at the end of the report. Closure call in the format function( $model, $key, $index)

Usage

echo ReportGrid::widget([
    'dataProvider' => $dataProvider,
    'columns' => $gridColumns,
    'controlBreak' => true,
    'totalRowOptions' => ['class'=>'total-row'],
    'totalsHeader' => true,
    'exportCSV' => true,
    'afterRow' => function( $model, $key, $index)  {
    	return $someContent;
    },
    'pageSummary' => [
            Html::tag('tr','<td colspan=10><h1>Report Summary goes here</h1></td>'),
    ]
    
    ]);

Column Configuration

When you use sub-totalling in a report, your report layout must follow the same structure as your query. So the first thing is to define your query with the results in the correct order.

When defining columns, you first need to specify which columns will cause your report to break. Normally, these will also be in the same order as the columns themselves but this is not mandatory.

  • subTotalOn : integer, The break level runs from 1 upwards and the gridview then uses level zero as the report totals.

  • subTotal : array | boolean, with the following options;
    • if set to true, then reportGrid uses the attribute value, summing the model->attribute or model->value amounts.
    • value : string|attribute name|closure ~ function($model, $key, $index, $widget, $break) {}, the value used by the totalling function as opposed to the value displayed.
    • breakValue : string|attribute name|closure ~ function($model, $key, $index, $widget, $break) {}, what to display in the sub-total cell. note the addition of the $break variable which can be used to determine the current break level. For example: you may use if ($break!=1) return $model->some_amount; else return ' ';
    • showOnBreak | hideOnBreak : integer, show/hide the sub-total at the specified break level
    • format : boolean, uses the yii2 formatter to pre-format the cell contents eg: currency, html, text
    • totalMethod : the only available option at this stage is ReportColumn::TOTAL_BREAKDOWN, This will provide a summary table at the control break of this column values and summed values specified by totalOn.
    • totalOn : string|attribute name|closure ~ function($model, $key, $index, $widget, $break) { return $model->attribute; },, the value to be applied to the totalling.

Usage

'subTotal' => [
       'breakValue' => function($model, $key, $index, $widget, $break) {
           if ($break == 1)
               return   $model->category_name; 
           elseif ($break == 0)
               return 'REPORT TOTAL';
       },
       'hideOnBreak' => 2
       ]
	

for more info see: yii2.percipero.com

]]>
0
[wiki] How to make UrlManager createAbsoluteUrl work with sub-domains Sun, 25 Mar 2018 02:06:47 +0000 https://www.yiiframework.com/wiki/858/how-to-make-urlmanager-createabsoluteurl-work-with-sub-domains https://www.yiiframework.com/wiki/858/how-to-make-urlmanager-createabsoluteurl-work-with-sub-domains wadeshuler wadeshuler

Upon creating my Yii2 Members System, I have ran into a few snags along the way that forced me to extend and bend Yii2 to my will.

I will describe how my app is intended to work, so you know how this article fits into your project needs. My members system is designed to resemble the good ole' days, when we had site.com/members and site.com/admin. It is common to also have them on sub-domains as members.site.com and admin.site.com . The sub-domains add an extra layer of security, especially with the admin on it's own sub-domain separate from the users. Now, that alone wont save you from everything, but as I said, it's just an extra layer. Some of us need them separated like this, because the sub-domains are on different servers. For example, your API could be on an independent server. Or maybe your users and admin sections are on different servers or IPs. If you look at large systems like Microsoft or Adobe, they have many servers for many different uses. Users, API, time, activation, fonts, and many more... So it isn't crazy to want your apps on different sub-domains.

Unfortunately, Yii2 is flat out retarded when it comes to sub-domains. Hopefully they will implement what I am about to show you, or a better version of this. I am always open to a better way to do this.

When I Googled this issue, there wasn't much out there. I found info related to how to link to backend from frontend, and that is even in the official Yii2 docs. That DOES NOT work with sub-domains though! It only works for directories, ie: what comes after your domain, not the sub-domain. I did find one GitHub repo from Postor. Problem was, it wasn't very intuitive and looks like a broken unfinished repo. So I feel the one I made was better.

So in this guide, I am going to show you the best and only way I found to create links to another one of your Yii apps (ie: backend or frontend) that are on a sub-domain.

My method for handling sub-domains

Unfortunately, there isn't an accurate and reliable way to grab only the domain name. A bunch of regex or stripping, or pulling from a huge list of valid domain extensions, etc. Nothing you want running on a site with tons of users, it will create a bottle neck real quick. Yeah, you could implement caching and you should for large volume sites. However, I prefer to cache lean efficient code instead of using caching to save my rear on terrible logic.

So this REQUIRES us to define our domain and sub-domains in our common bootstrap file.

common/config/bootstrap.php

// URL Manager Aliases
Yii::setAlias('@domainName', (YII_ENV === 'dev') ? 'yii2-members-system.dev' : 'yourlivesite.com');
Yii::setAlias('@frontendSubdomain', 'users');
Yii::setAlias('@backendSubdomain', 'admin');

Create common/components/UrlManager.php

<?php
namespace common\components;

use Yii;
use yii\helpers\Url;
use yii\base\InvalidConfigException;

class UrlManager extends yii\web\UrlManager
{
    public $subDomain;
    public $domainName;

    protected $_hostInfo;

    public function getProperDomain()
    {
        if ( ! isset($this->domainName) || empty($this->domainName) ) {
            throw new InvalidConfigException('Request requires a domain name to be configured!');
        }

        $subDomain = (isset($this->subDomain) && !empty($this->subDomain)) ? $this->subDomain : '';
        $domain = empty($subDomain) ? '' : $subDomain . '.';
        $domain .= $this->domainName;

        return $domain;
    }

    public function getHostInfo()
    {
        if ($this->_hostInfo === null)
        {
            $secure = Yii::$app->getRequest()->getIsSecureConnection();
            $http = $secure ? 'https' : 'http';

            if (isset($_SERVER['HTTP_HOST'])) {
                $this->_hostInfo = $http . '://' . $this->getProperDomain();
            } elseif (isset($_SERVER['SERVER_NAME'])) {
                $this->_hostInfo = $http . '://' . $this->getProperDomain();
                $port = $secure ? $this->getSecurePort() : $this->getPort();

                if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) {
                    $this->_hostInfo .= ':' . $port;
                }
            }
        }
        return $this->_hostInfo;
    }

}

Now in whichever app your needing to link to another subdomain, you need to edit it's main config. So if in backend you need to link to frontend (or mainsite needs to link to frontend as in my members system), then edit your backend config.

Add this to your config under the components array:

'urlManagerFrontend' => [
    'class' => 'common\components\UrlManager',
    'subDomain' => Yii::getAlias('@frontendSubdomain'),
    'domainName' => Yii::getAlias('@domainName'),
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'rules' => [
    ],
],

Now, wherever you need to create a link (or get the url for any reason) use CreateAbsoluteUrl inside the new UrlManager like so:

Yii::$app->urlManagerFrontend->createAbsoluteUrl(['site/login'])

In my app, it generates a link for my mainsite to the users app: http://users.yii2-members-system.dev/site/login. This was so on my mainsite I can link to the user's subdomain for them to login.

I hope this helps someone, and I hope Yii actually adopts a solution for this sort of linking and handling sub-domains.

]]>
0
[wiki] Show raw SQL query Sat, 14 Jan 2017 19:53:41 +0000 https://www.yiiframework.com/wiki/857/show-raw-sql-query https://www.yiiframework.com/wiki/857/show-raw-sql-query darioo darioo

Here's a quick tip to dump the SQL for query.

$query = new Books::find()->where('author=2');
echo $query->createCommand()->sql;

or to get the SQL with all parameters included try:

$query->createCommand()->getRawSql()

Thanks to http://chris-backhouse.com/Yii2-Output-the-SQL-from-a-query-builder/1027

]]>
0
[wiki] Working with relational removals by yii2 Mon, 05 Jun 2017 03:57:13 +0000 https://www.yiiframework.com/wiki/856/working-with-relational-removals-by-yii2 https://www.yiiframework.com/wiki/856/working-with-relational-removals-by-yii2 androidelp androidelp

This tutorial shows you how to safely remove records between relationships.

First we create three tables using a Many to Many relationship.

Imagem da relacao

Important: Apply cascade to foreign key constraints for update and delete.

The cascade feature will allow you to remove the foreign keys along with the line you want to delete and helps keep your code to a minimum.

Script SQL the ralation has.

CREATE TABLE `tests_has_games` (
   `tests_id` int(11) NOT NULL,
   `games_id` int(11) NOT NULL,
   PRIMARY KEY (`tests_id`,`games_id`),
   KEY `fk_tests_has_games_games1_idx` (`games_id`),
   KEY `fk_tests_has_games_tests_idx` (`tests_id`),
   CONSTRAINT `fk_tests_has_games_games1` FOREIGN KEY (`games_id`) REFERENCES `games` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
   CONSTRAINT `fk_tests_has_games_tests` FOREIGN KEY (`tests_id`) REFERENCES `tests` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin

Step 2: Create models: (to use generator gii, this system create model with relations of the table). ModelGames:

public function getTestsHasGames()
    {
        return $this->hasMany(TestsHasGames::className(), ['games_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getTests()
    {
        return $this->hasMany(Tests::className(), ['id' => 'tests_id'])->viaTable('{{%tests_has_games}}', ['games_id' => 'id']);
    }

Model Tests:

public function getTestsHasGames()
    {
        return $this->hasMany(TestsHasGames::className(), ['tests_id' => 'id']);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getGames()
    {
        return $this->hasMany(Games::className(), ['id' => 'games_id'])->viaTable('{{%tests_has_games}}', ['tests_id' => 'id']);
    }

Step 3: Simple Removal Functions in controllers:

public function actionDeletarTest($id)
  {

    $session = \Yii::$app->session;

    $testes = Tests::findOne($id);

    if($testes->delete())
    {
      $session->addFlash('resposta', [
        'type'=>'success',
        'msg'=>'Teste deletado com sucesso.'
      ]);
    }else{
      $session->addFlash('resposta', [
        'type'=>'danger',
        'msg'=>'Erro encontrado favor resolver.'
      ]);
    }

    return $this->redirect(['site/delete-relations']);

  }

Other Methods

public function actionDeleteListGames()
  {
    $array_id = [1,2,3,4];

    $games = Games::find()->where(['in','id',$array_id])->all();

    foreach($games as $k => $game)
    {
      $game->delete();
    }

  }
     // deletando de vinculo
     public function actionDeleteTestAll()
     {
       $game = Games::findOne(1);
       foreach($game->tests as $test)
       {
          $test->delete();
       }
     }


public function actionDeleteTheRelation($id)
  {


    $game = Games::find()->joinWith(['tests'=>function($q){
      return $q->where(['like','nome','proccess'])
    }])->where(['id'=>$id])->one();

    foreach($games->tests as $k => $test)
    {
      $test->delete();
    }

  }

Get All code in Your text to link here...

]]>
0
[wiki] Interactive mode command-line command for Yii1 Mon, 21 Nov 2016 12:41:10 +0000 https://www.yiiframework.com/wiki/854/interactive-mode-command-line-command-for-yii1 https://www.yiiframework.com/wiki/854/interactive-mode-command-line-command-for-yii1 trejder trejder

For one of my projects I needed an interactive console command in Yii 1, i.e. the one that is gathering all information from user in an interactive mode (a serie of questions and answers displayed directly in the console), ignoring command-line arguments at all.

This is an example (or rather a bare foundation, as this actually is doing nothing) of such solution. It has some console text formatting methods (borders, text alignment) plus simple method for gathering user response.

The code

Here is an implementation for Yii 1 of mentioned solution.

class ImportCommand extends CConsoleCommand
{
    const BORDER_WIDTH = 80;

    public function actionIndex($args)
    {
        $message = $this->alignText('This text is aligned to the right border...', 'right')."\n";
        $message .= "\n";
        $message .= $this->alignText('...this one is centered...', 'center')."\n";
        $message .= "\n";
        $message .= $this->alignText('...and this is left as is, so aligned to the left border!', 'left')."\n";
        $message .= "\n\n";
        $message .= $this->alignText('Finally we have a really long text, no matter, how aligned, that is going to be cut right there, where it should');

        $this->drawBorder($message);

        $this->readStdin();

        echo 'You selected: '.$this->readStdin('Enter any alphabet letter, please...');
        
        $this->clearStdin();
    }

    /**
     * Aligns text to given margin.
     * 
     * @param  string $text       Text to be aligned.
     * @param  string $align      Align method: 'right', 'center' or 'left' (default == empty string).
     * @param  integer $lineWidth Maximim line width. If not specified, class' constant will be used instead.
     * 
     * @return string             Aligned text, pad with trailing and following spaces.
     */
    public function alignText($text, $align = 'left', $lineWidth = null)
    {
        $lineWidth = is_null($lineWidth) ? self::BORDER_WIDTH : $lineWidth;
        $lineWidth = $lineWidth - 4;

        $text = strlen($text) > $lineWidth ? substr($text, 0, $lineWidth) : $text;

        if($align === 'right')
        {
            return str_repeat(' ', $lineWidth - strlen($text)).$text;
        }

        if($align === 'center')
        {
            $margin = floor($lineWidth  / 2) - floor(strlen($text) / 2);

            return str_repeat(' ', $margin).str_pad($text, $margin , ' ');
        }
        else return $text;
    }

    /**
     * Draws console-like (DOS-like?) text border around passed text.
     * 
     * @param  string $text       Text to be outlined in a fancy-like text border.
     * @param  integer $lineWidth Maximim width of each border line. See above for details.
     */
    public function drawBorder($text, $lineWidth = null)
    {
        $lineWidth = is_null($lineWidth) ? self::BORDER_WIDTH : $lineWidth;
        $lineWidth = $lineWidth > 80 ? 80 : $lineWidth;

        $nl = $lineWidth === 80 ? '' : "\n";

        echo str_repeat('*', $lineWidth).$nl;

        echo '*'.str_repeat(' ', $lineWidth - 2).'*'.$nl;

        foreach(explode("\n", $text) as $line) echo '* '.str_pad($line, $lineWidth - 4, ' ').' *'.$nl;

        echo '*'.str_repeat(' ', $lineWidth - 2).'*'.$nl;

        echo str_repeat('*', $lineWidth).$nl;
    }

    /**
     * Get user entry / decision.
     * 
     * @param  string $message Information to be displayed, when requiring user to enter something.
     * 
     * @return string          User entry.
     */
    public function readStdin($message = 'Continue [Y/N]?')
    {
        echo $message;

        $handle = fopen("php://stdin","r");
        $line = fgets($handle);

        return trim($line);
    }
    
    /**
     * Clears console window.
     *
     * The implementation used here can't be anymore ugly, but it is the only one,
     * that is working, when using GitBash. All other methods fails:
     *
     * http://stackoverflow.com/a/24327758/1469208
     * http://stackoverflow.com/a/29193143/1469208
     */
    public function clearStdin()
    {
        for ($i = 0; $i < 50; $i++) echo "rn";
    }
}

Execution

To get this thing working, put all the above code in a separate .php file and save it to protected/commands path under ImportCommand.php name.

Then open console window, navigate to protected folder in your application and execute:

yiic import

Of course, rename both file and class name, if you want to use this command under different name.

Also make sure that you have set correctly everything around running console commands.

]]>
0
[wiki] REST API and null values in XML Fri, 11 Nov 2016 00:26:44 +0000 https://www.yiiframework.com/wiki/853/rest-api-and-null-values-in-xml https://www.yiiframework.com/wiki/853/rest-api-and-null-values-in-xml marko60 marko60

I have been working on a REST API using the excellent tools provided by Yii2. My problem was that I have to differentiate between empty values and null values. In other words, <elem></elem> is different from null as it represents an empty string. Also, although some use <elem/> to represent a null value it should still be interpreted as an empty string. In other cases, the absence of the element is taken to represent a null value, but this may create problem with some parsers.

After some research, it appears that the correct way of describing a null value is <elem xsi:nil="true"/>.

However this is not supported by the current implementation of XmlResponseFormatter because values are always appended as DOMText. This means that, even is I pass a PHP null value, I get <elem></elem>.

Therefore, I have extended XmlResponse Formatter as follows.

Firstly, the function format() must be modified because creating $root as DOMElement makes it immutable while I need to attach the xsi: namespace definition. Therefore I use:

...
$dom = new DOMDocument($this->version, $charset);
// A writeable element is created and the namespace added
$root = $dom->createElement($this->rootTag);
$root->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$dom->appendChild($root);
...

Then I have modified the buildXml function as follows:

protected function buildXml($element, $data){
  if (is_array($data) ||
    ($data instanceof \Traversable && $this->useTraversableAsArray && !$data instanceof Arrayable)
  ) {
    foreach ($data as $name => $value) {
      if (is_int($name) && is_object($value)) {
        $this->buildXml($element, $value);
      } elseif (is_array($value) || is_object($value)) {
        $child = new DOMElement(is_int($name) ? $this->itemTag : $name);
        $element->appendChild($child);
        $this->buildXml($child, $value);
      } else {
        $child = new DOMElement(is_int($name) ? $this->itemTag : $name);
        $element->appendChild($child);
        // Checks if the value is null and creates a null MXL element
        if ($value === null) {
          $child->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance','xsi:nil','true');
        } else {
          $child->appendChild(new DOMText((string) $value));
        }
      }
    }
  } elseif (is_object($data)) {
    $child = new DOMElement(StringHelper::basename(get_class($data)));
    $element->appendChild($child);
    if ($data instanceof Arrayable) {
      $this->buildXml($child, $data->toArray());
    } else {
      $array = [];
      foreach ($data as $name => $value) {
        $array[$name] = $value;
      }
      $this->buildXml($child, $array);
    }
  } else {
    // Checks if $data is null and adds xsi:nil to $element
    if ($data === null) {
      $element->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance','xsi:nil','true');
    } else {
      $element->appendChild(new DOMText((string) $data));
    }
  }
}

This way, if the value of the XML element is null, I get <element xsi:nil="true"/> which is more correct while, if the value is an empty string, I get <element></element> as expected.

I hope this would be useful to somebody and maybe the Yii2 could consider this improvement in a future release.

]]>
0
[wiki] Optimize Scenarios for yii2 Thu, 12 Apr 2018 13:24:16 +0000 https://www.yiiframework.com/wiki/852/optimize-scenarios-for-yii2 https://www.yiiframework.com/wiki/852/optimize-scenarios-for-yii2 androidelp androidelp

Working with scenarios, with models that can receive many modifications in their rules or structures as development evolves, can create disruptions in the rescue process.

One way to avoid this disorder is to encapsulate the information defined for the scenarios and to have a single point of customization.

For this we need to create constants for each scenario, note: once you define a scenario, you will need to use scenarios for any database edition that uses this model.

In model

class MyModel extends \yii\db\ActiveRecord
{

  const SCENARIOCRIATE = 'scenariocriate';
  const SCENARIOUPDATE = 'scenarioupdate';

    // scenarios encapsulated
    public function getCustomScenarios()
    {
      
      return [
          self::SCENARIOCRIATE      =>  ['user_id', 'name', 'desc', 'published','date_create'],
          self::SCENARIOUPDATE      =>  ['user_id', 'name', 'desc', 'date_update'],
      ];
    }
    // get scenarios
    public function scenarios()
    {
        $scenarios = $this->getCustomScenarios();
        return $scenarios;
    }

    // modify itens required for rules
    public function ModifyRequired()
    {

      $allscenarios = $this->getCustomScenarios();
      // published not required
      $allscenarios[self::SCENARIOCRIATE] = array_diff($allscenarios[self::SCENARIOCRIATE], ['published']);
      return $allscenarios;

    }

    public function rules()
    {
      // get scenarios
      $allscenarios = $this->ModifyRequired();
        return [
            [$allscenarios[self::SCENARIOCRIATE], 'required', 'on' => self::SCENARIOCRIATE],
            [$allscenarios[self::SCENARIOUPDATE], 'required', 'on' => self::SCENARIOUPDATE],
            [['user_id'], 'integer'],
            [['name','desc'], 'string', 'max' => 70],
            [['date_create', 'date_update'], 'date', 'format' => 'php:Y-m-d H:i:s'],
        ];
    }

GetCustomScenarios will be used for when you need to make column modifications.

The ModifyRequired is used to remove from the required, because at this point will be used getCustomScenarios for the save.

In Controller

public function actionIndex()
{

    $model = new MyModel;
    $model->scenario = 'scenariocriate';

    if ($model->load(\Yii::$app->request->post())){

        // force my columns
        if($model->save()){
          //return true
        } 
    }
}

It may seem redundant, but constructing the controller in this way, avoids having problems with maintenance of database tables, the adjustments will be made only in the model, since there is no reference of communes in the controller.

]]>
0
[wiki] Yii2 GridView Sorting and Searching with a Junction Table Column(Many to Many Relationship) Tue, 08 Nov 2016 02:34:38 +0000 https://www.yiiframework.com/wiki/851/yii2-gridview-sorting-and-searching-with-a-junction-table-columnmany-to-many-relationship https://www.yiiframework.com/wiki/851/yii2-gridview-sorting-and-searching-with-a-junction-table-columnmany-to-many-relationship Amjad Khan Amjad Khan
  1. tblgroups
  2. tblcontacts
  3. tblcontactsgroups(junction table)

Following is the table structure

tblgroups

CREATE TABLE IF NOT EXISTS `tblgroups` (
  `id` int(11) NOT NULL,
  `groupname` varchar(150) NOT NULL,
  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1=Acitve,2=Inactive',
  `date` datetime NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

tblcontacts

CREATE TABLE IF NOT EXISTS `tblcontacts` (
  `id` int(11) NOT NULL,
  `firstname` varchar(100) NOT NULL,
  `lastname` varchar(100) NOT NULL,
  `company` varchar(100) NOT NULL,
  `address` text NOT NULL,
  `phone` varchar(50) NOT NULL,
  `mobile` varchar(50) NOT NULL,
  `fax` varchar(50) NOT NULL,
  `pemail` varchar(100) NOT NULL,
  `semail` varchar(100) NOT NULL,
  `country` varchar(55) NOT NULL,
  `websiteurl` varchar(100) NOT NULL,
  `gender` tinyint(4) NOT NULL COMMENT '1=male,2=female,3=shemale',
  `birthday` varchar(10) NOT NULL,
  `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1=Active,2=Inactive',
  `sentstatus` tinyint(4) NOT NULL DEFAULT '1' COMMENT '1=sent,2=not sent',
  `addeddate` datetime NOT NULL,
  `updateddate` datetime NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;

tblcontactsgroups(junction table)

CREATE TABLE IF NOT EXISTS `tblcontactsgroups` (
  `id` int(11) NOT NULL,
  `contact_id` int(11) NOT NULL,
  `group_id` int(11) NOT NULL,
  `dateadded` datetime NOT NULL
) ENGINE=MyISAM AUTO_INCREMENT=20085 DEFAULT CHARSET=latin1;

First of all with the help of gii crud generators we will create the crud for all these tables including models and controllers,tblcontactsgroups is the table having many to many relation between tblcontacts and tblgroups. In the Contacts Model generated from tblcontacts we will use the hasMany relationship as follows

public function getGroups() {
        return $this->hasMany(Groups::className(), ['id' => 'group_id'])->viaTable('tblcontactsgroups', ['contact_id' => 'id']);
    }

In Groups model we will insert the following code

public function getContacts() {
        return $this->hasMany(Contacts::className(), ['id' => 'contact_id'])->viaTable('tblcontactsgroups', ['group_id' => 'id']);
    }

The most important model is the ContactsSearch Model we will make the following changes in it first of all we declare the groupname(related groups table attribute) public property in ContactsSearch Model

class ContactsSearch extends Contacts {

    /**
     * @inheritdoc
     */
    // public group_id;
    public $groupname;
............................

we will also include groupname in the rules

public function rules() {
        return [
            [['id', 'gender', 'status', 'sentstatus'], 'integer'],
            [['firstname', 'lastname', 'company', 'address','groupname', 'phone', 'mobile', 'fax', 'pemail', 'semail', 'country', 'websiteurl', 'birthday', 'addeddate', 'updateddate'], 'safe'],
        ];
    }

and then we will manipulate the search method in ContactsSearch Model like this

public function search($params) {
        $query = Contacts::find()->innerJoinWith('groups', true);
        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'sort' => ['attributes' => ['firstname', 'lastname', 'groupname', 'email', 'pemail']]
        ]);

        $this->load($params);
        if (!$this->validate()) {
            // uncomment the following line if you do not want to return any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }

        // grid filtering conditions
        $query->andFilterWhere([
            'id' => $this->id,
            'gender' => $this->gender,
            'status' => $this->status,
            'sentstatus' => $this->sentstatus,
            'addeddate' => $this->addeddate,
            'updateddate' => $this->updateddate,
        ]);

        $query->andFilterWhere(['like', 'firstname', $this->firstname])
                ->andFilterWhere(['like', 'lastname', $this->lastname])
                ->andFilterWhere(['like', 'company', $this->company])
                ->andFilterWhere(['like', 'address', $this->address])
                ->andFilterWhere(['like', 'phone', $this->phone])
                ->andFilterWhere(['like', 'mobile', $this->mobile])
                ->andFilterWhere(['like', 'fax', $this->fax])
                ->andFilterWhere(['like', 'pemail', $this->pemail])
                ->andFilterWhere(['like', 'semail', $this->semail])
                ->andFilterWhere(['like', 'country', $this->country])
                ->andFilterWhere(['like', 'websiteurl', $this->websiteurl])
                ->andFilterWhere(['like', 'birthday', $this->birthday])
                ->andFilterWhere(['like', 'groupname', $this->groupname]);

        return $dataProvider;
    }

Following is the code for the ContactsController no change just gii generated code

public function actionIndex()
    {
        $searchModel = new ContactsSearch();
      
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
    
        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

Following is the code for the gridview

GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],
            [
                'label' => 'First Name',
                'attribute' => 'firstname',
            ],
            [
                'label' => 'Last Name',
                'attribute' => 'lastname',
            ],
            //  'company',
            // 'address:ntext',
            // 'phone',
            // 'mobile',
            // 'fax',
    //Following is the related column from the groups table
            [
                'label' => 'Groups',
                'format' => 'ntext',
                'attribute'=>'groupname',
                'value' => function($model) {
                    foreach ($model->groups as $group) {
                        $groupNames[] = $group->groupname;
                    }
                    return implode("\n", $groupNames);
                },
            ],
            [
                'label' => 'Primary Email',
                'attribute' => 'pemail',
            ],
            // 'semail:email',
            // 'country',
            // 'websiteurl:url',
            // 'gender',
            // 'birthday',
            // 'status',
            // 'sentstatus',
            // 'addeddate',
            // 'updateddate',
            ['class' => 'yii\grid\ActionColumn'],
        ],
    ]);
    ?>

In this way you can show the related groupname in the contacts model with sorting and searching facility.

Thanks

]]>
0
[wiki] How to customize your grid columns visible and order by user themselves Fri, 14 Oct 2016 10:17:54 +0000 https://www.yiiframework.com/wiki/850/how-to-customize-your-grid-columns-visible-and-order-by-user-themselves https://www.yiiframework.com/wiki/850/how-to-customize-your-grid-columns-visible-and-order-by-user-themselves Scott_Huang Scott_Huang
  1. Goal
  2. Sample Picture
  3. Add code in controller
  4. Add code in model
  5. Adjust your view code
  6. a.Register JS
  7. b.Show Config Columns link
  8. c.Add partial render code in your view file
  9. d.That partial render real file
  10. Some Help Functions

Goal

Cusomized your grid columns by user themselves, allow user to hide/show columns or re-order the columns sequences.

Sample Picture

The final result look like below, you can hide/show any columns. You can type the order to re-sort the columns after save the config. You can input -1 to put it in first columns. After save, the index will reorder from 1 to the max.

The export to excel function will affected by the final resorted columns in case you use my export grid to excel extends hzlexportgrid too, Since that export extention just depends on the grid columns configs, and that columns been customized by user themselves just now.

Sample Picture

Add code in controller

Below code will help you save user configs or reset it and redirect to the destination

Some helper function list details in last session, you can deep dive HzlUtil::xxxFunction later

//your other controller code
if (isset($_POST['columnsVisibleConfigArr'])) {
            HzlUtil::saveConfigColumns(NPIPartRegion::BuyerViewColumnSetting, $_POST['columnsVisibleConfigArr']);
            //we need save to user config
        }
        if (isset($_POST['resetColumnsVisibleConfigArr'])) {
//            HzlUtil::dump($_POST['resetColumnsVisibleConfigArr']);
            HzlUtil::deleteConfigColumns(NPIPartRegion::BuyerViewColumnSetting);
            $this->redirect(array("NPIPartRegion/searchNPI"));//you can set to your index file
        }

Add code in model

I assume your grid column get from your model. such as $model->yourGridColumn() instead input in your view file directly.

public function BuyerColumns($specificId)
    {
//you can ignore/remove $specificId parameter, it just use in my own code:)
        $columnsByRole =  array(
//'id',
//'Part_Id',
            'id',
//            'Is_Primary',
            array(
                'name' => 'Is_Primary',
                'header' => 'Is_Primary',
                'value' => '$data->Is_Primary==1?"Yes":"No"',
                'filter' => NPIPart::itemAlias('Yes_No'),
                'cssClassExpression' => '$data->Is_Primary==1?"green":"grey"'
            ),
//... many other arrays
'Note',
            'Platform_GSM_Note',
//    'Update_At',
            array('name' => 'Create_At', 'header' => 'Region_Create_At')
        );

//Need read columns settings
//This is the key codes, it try to get existing configs, and try to merge into current grid columns
        $settings = Yii::app()->settings;
        $userId = "User" . yii::app()->user->id;
        $configColumns = $settings->get($userId, NPIPartRegion::BuyerViewColumnSetting);
        //and adjust default grid columns by the saved customized columns settings.
        $columnsByRole = HzlUtil::mergeConfigColumns($columnsByRole, $configColumns);
        return $columnsByRole;
}

Adjust your view code

So, you complete adjust your controller, and model, not it is the time to adjust your view code.

It is quite similar as search funtion, you click the "Config Column" link, it will expand the columns for user to setting, click the save config button, will adjust grid immediately

a.Register JS

Add below code into view file, it try to register the JS. Note, the #npipart-region-grid id need change to your own grid id. You can paste below code right after your old JS code in your view file

Yii::app()->clientScript->registerScript('config-columns', "
$('.config-columns-button').click(function(){
	$('.config-columns').toggle();
	return false;
});
$('.config-columns form').submit(function(){
	$('#npipart-region-grid').yiiGridView('update', {
		data: $(this).serialize()
	});
        $('.config-columns').toggle();
        //return false;
});
");

$columnsByRole = $model->BuyerColumns($specificId);

$columnsByRole will use in your grid. The parameter $specificID you can ignore or remove. $model->BuyerColumns($specificId) defined before, you can replace by your own get columns function:) just need to do some special handles in that function. It state before, let me highlight again below:

//your get column function need add below at the end
        $settings = Yii::app()->settings;
        $userId = "User" . yii::app()->user->id;
        $configColumns = $settings->get($userId, NPIPartRegion::BuyerViewColumnSetting);
        //and adjust default grid columns by the saved customized columns settings.
        $columnsByRole = HzlUtil::mergeConfigColumns($columnsByRole, $configColumns);
        return $columnsByRole;

b.Show Config Columns link

Add below code under the search link, it try to show the "Config Columns" link. You can adjust style by yourself, just need keep that 'class' => 'config-columns-button'

<?php echo str_repeat("&nbsp",10).CHtml::link('<b><font color = "red"> </font>Config Columns<font color = "red"> </font></b>', '#', array('class' => 'config-columns-button')); ?>

c.Add partial render code in your view file

Usually you have search code in your view file, please add below config columns code right after it. It try to partial render the _columnsVisibleConfig.php .

<div class="config-columns" style="display:none" >
    <!--<div class="search-form1" >-->
    <?php
    $this->renderPartial('_columnsVisibleConfig', array(
        'model' => $model,
        'columnsVisibleConfigArr'=>HzlUtil::getConfigColumns($columnsByRole),
        'gridLength' => 14  //you can adjust the number here, for example in case 54 columns, then the config will show as 4 grids, since 14*4=56 > 54.  Thanks.
    ));
    ?>
</div><!-- search-form -->


//other your codes
//your grid may be like below
$this->widget(
        'bootstrap.widgets.TbExtendedGridView', array(
    'id' => 'npipart-region-grid',
    'filter' => $model,
    'fixedHeader' => true,
    'type' => 'bordered hover',
    //'headerOffset' => 40,
    // 40px is the height of the main navigation at bootstrap
    'dataProvider' => $model->search(true, $specificId),
    'template' => "{pager}{summary}{items}{summary}{pager}",
    'enablePagination' => true,
    'columns' => $columnsByRole,  //note here, we use the columns which been handled in advance.
    'pager' => array(
        'class' => 'bootstrap.widgets.TbPager',
        'displayFirstAndLast' => true,
    ),
        )
);


d.That partial render real file

Usually it put in your view folder, name as _columnsVisibleConfig.php And then you can partial render this file in your view file.

<?php
$tempGridLength = $gridLength; 
?>

<div class="form">
    <div class="span18" style="font-size:83%">
        <?php
        echo CHtml::beginForm();
        $tempJ = 0;
        foreach ($columnsVisibleConfigArr as $tempI => $tempItem):
            if ($tempJ % $tempGridLength == 0) { //echo grid head
                echo '
                <div class="span3">
                <div class="grid-view">
                <table class="items" >
                <tr>
                    <th style="width:20%">Order#</th>
                    <th>Column Name</th>
                    <th>Hide</th>
                </tr>';
            }
            if ($tempJ % 2 == 0)
        {echo '<tr class = "even" style = "height:80%" > ';}
            else
        {echo '<tr class = "odd" style = "height:80%">';}
            ?>
            <td ><?php echo CHtml::textField("columnsVisibleConfigArr[$tempI][order]", $tempItem["order"], ['min' => 1, 'max' => 100, 'style'=>"width:30%;font-size:83%"]); ?></td>
            <td ><?php echo CHtml::textField("columnsVisibleConfigArr[$tempI][name]",$tempItem["name"],['readonly'=>'readonly','style'=>"width:80%;font-size:83%" ]); ?></td>
            <td><?php echo CHtml::checkBox("columnsVisibleConfigArr[$tempI][hide]",$tempItem["hide"],[]) ?></td>
            </tr>
            <?php
            $tempJ += 1;
            if ($tempJ == $tempGridLength) {
            echo '
                </table>
                </div>'.
                                CHtml::submitButton('Save Column Config',['style'=>"width:50%;font-size:83%"]).'
                </div> ';
                $tempJ = 0;
          }
        endforeach;
        if ($tempJ <> $tempGridLength) {
            echo '
                </table>
                </div>' .
                CHtml::submitButton('Save Column Config',['style'=>"width:50%;font-size:83%"]) . '
                </div> ';
        }
        ?>
        <?php

        echo str_repeat("&nbsp",10)."<font color = 'red'>Reset to Default Columns Config?! </font>".CHtml::checkBox("resetColumnsVisibleConfigArr",false,[]);
        echo CHtml::endForm(); ?>
    </div>
</div>

Some Help Functions

You can put it in your public component file or other file which you can access later. In my example, I put into components/HzlUtil.php file

// get columns name form gived grid columns
    public static function getConfigColumns($columns = [])
    {
        if (!is_array($columns)) {
            return [];
        }
        $columnsVisibleConfigArr = [];
        foreach ($columns as $i => $item) {
            $thisColumn = [];
            if (is_array($item)) {
                if (isset($item['header'])) {
                    $thisColumn['name'] = str_replace("&nbsp", "", $item['header']);
                } elseif (isset($item['name'])) {
                    $thisColumn['name'] = $item['name'];
                }
                if (isset($item['visible'])) {
                    $thisColumn['hide'] = !$item['visible'];
                } else {
                    $thisColumn['hide'] = false;
                }
            } else {
                $thisColumn['name'] = $item;
                $thisColumn['hide'] = false;
            }
            $thisColumn['order'] = $i + 1;

            $columnsVisibleConfigArr[] = $thisColumn;
        }
        return $columnsVisibleConfigArr;
    }


//we leverage CmsSettings extension to save configs to DB.  Detail info like below, you can search from Yii forum to install in your yii1.0 system in advance. Thanks.
//Actually, I just copy that file in components folder
/**
 * CmsSettings
 * 
 * @package OneTwist CMS  
 * @author twisted1919 (cristian.serban@onetwist.com)
 * @copyright OneTwist CMS (www.onetwist.com)
 * @version 1.2
 * @since 1.0
 * @access public
 *
 * 1.1e - Special thanks to Gustavo (http://www.yiiframework.com/forum/index.php?/user/6112-gustavo/)
 */

    public static function saveConfigColumns($gridCategory = '', $gridConfig = [])
    {
        usort($gridConfig, function ($a, $b) {
            $al = intval($a["order"]);
            $bl = intval($b["order"]);
            return $al == $bl ? 0 : ($al > $bl ? 1 : -1);
        });
        foreach ($gridConfig as $i => $item) {
            $gridConfig[$i]["order"] = $i + 1;
            if (!isset($item["hide"])) {
                $gridConfig[$i]["hide"] = false;
            } else if ($item["hide"]) {
                $gridConfig[$i]["hide"] = true;
            }
        }
//we leverage the CmsSettings extention here
        $settings = Yii::app()->settings;
        $userId = "User" . yii::app()->user->id;
        $settings->set($userId, $gridCategory, $gridConfig);
    }

    public static function deleteConfigColumns($gridCategory = ''){
        $settings = Yii::app()->settings;
        $userId = "User" . yii::app()->user->id;
        $settings->delete($userId, $gridCategory);
        HzlUtil::setMsg("Success Delete Config","Success delete the columns config.");
    }

    //  configColumns: each item contain order,name,hid fields
    public static function mergeConfigColumns($defaultColumns, $configColumns)
    {
        if (empty($configColumns)) {
            return $defaultColumns;
        } else {
            $FinalColumnsByRole = [];
            foreach ($configColumns as $i => $item) {
                foreach ($defaultColumns as $j => $defaultItem) {
                    $thisDefaultItemName = 'NotExistingN/A';
                    if (is_array($defaultItem)) {
                        if (isset($defaultItem['header'])) {
                            $thisDefaultItemName = str_replace("&nbsp", "", $defaultItem['header']);
                        } elseif (isset($defaultItem['name'])) {
                            $thisDefaultItemName = $defaultItem['name'];
                        }
                    } else {
                        $thisDefaultItemName = $defaultItem;
                    }
                    if ($thisDefaultItemName == $item['name']) {//find that column
                        if ($item['hide']) {
                            if (is_array($defaultItem)) {
                                $defaultItem['visible'] = false;
                                $FinalColumnsByRole[] = $defaultItem;
                            } else {
                                $newDefaultItem = [];
                                $newDefaultItem['name'] = $defaultItem;
                                $newDefaultItem['visible'] = false;
                                $FinalColumnsByRole[] = $newDefaultItem;
                            }
                        } else {
                            $FinalColumnsByRole[] = $defaultItem;
                        }
                        unset($defaultColumns[$j]);//this is important
                        break;
                    }
                }
            }
            //need append left default to final columns
            foreach ($defaultColumns as $j => $defaultItem) {
                $FinalColumnsByRole[] = $defaultItem;
            }
            return $FinalColumnsByRole;
        }
    }

]]>
0
[wiki] How to make bootstrap tabs remain active/selected after navigating to different web pages. Fri, 07 Oct 2016 15:36:28 +0000 https://www.yiiframework.com/wiki/849/how-to-make-bootstrap-tabs-remain-activeselected-after-navigating-to-different-web-pages https://www.yiiframework.com/wiki/849/how-to-make-bootstrap-tabs-remain-activeselected-after-navigating-to-different-web-pages emrald_gem emrald_gem

Bootstrap tabs gets unselected/inactive when user navigates to other page and comes back. How to make bootstrap tabs remain active/selected after navigating to different web pages.

Steps :> 1: Add class dashboard_tabs_cl to <ul>.

<!-- Nav tabs -->
<ul class="nav nav-tabs dashboard_tabs_cl" role="tablist">

2: Add javascript to the page.

<?php $this->registerJs(
'$("document").ready(function(){
	if (typeof(Storage) !== "undefined") {
				
		var dash_localVar = localStorage.getItem("dash_activ_tab"+getUrlPath());
		if(dash_localVar){

			$(".dashboard_tabs_cl > li").removeClass("active");
			$(".tab-content > div").removeClass("active");

			var hrefAttr = "a[href=\'"+dash_localVar+"\']";
			if( $(hrefAttr).parent() ){
				$(hrefAttr).parent().addClass("active");
				$(""+dash_localVar+"").addClass("active");
			}
				
		}

		$(".dashboard_tabs_cl a").click(function (e) {
			//alert(window.location.pathname);					
			e.preventDefault();
			localStorage.setItem("dash_activ_tab"+getUrlPath(), $( this ).attr( "href" ));
		});
		function getUrlPath(){
			var returnVar = "_indexpg";
			var splitStr = window.location.href;
			var asdf = splitStr.split("?r=");
			if(asdf[1]){
				var furthrSplt = asdf[1].split("&");
				if(furthrSplt[0]){
					returnVar = furthrSplt[0];
				}else{
					returnVar = asdf[1];
				}
			}
			return returnVar;
		}
	}
	});'
); ?>

Done!.

]]>
0
[wiki] Installation guide: Yii-2 advanced template with RBAC system Mon, 22 Aug 2016 07:04:06 +0000 https://www.yiiframework.com/wiki/848/installation-guide-yii-2-advanced-template-with-rbac-system https://www.yiiframework.com/wiki/848/installation-guide-yii-2-advanced-template-with-rbac-system sherin_jose_yii sherin_jose_yii

Welcome, all of you !

Here I am giving the steps for an easy installation of yii2-advanced template with an RBAC(Role Based Access Control) system.

Installtion : Yii2 - advanced template

Here we are going to install yii2-advanced template using composer. So if you don't have composer in your machine, please download and install the latest version of it. After installing composer please check whether it is accessible from the CMD by running the command composer like:

C:\>composer

If the above command gives a +ve response, then it's okay. Now we can start.

Open a new CMD window and locate to your server root directory. I am using wamp server so myself would be like:

C:\>cd wamp\www
C:\wamp\www>

Then run the command composer create-project --prefer-dist yiisoft/yii2-app-advanced yii2-app for creating a new application named as yii2-app like:

C:\wamp\www>composer create-project --prefer-dist yiisoft/yii2-app-advanced yii2-app

The template will be downloaded from git repository. After the template is installed, locate to the newly created application directory C:\wamp\www\yii2-app in CMD like:

C:\wamp\www>cd yii2-app
C:\wamp\www\yii2-app>

Then you should initialize the application by running php init in CMD. The initialization will generate the entry scripts and config files for your application. Run the command like:

C:\wamp\www\yii2-app>php init

You can select the environment type from the given options:

Which environment do you want the application to be initialized in?

  [0] Development
  [1] Production

  Your choice [0-1, or "q" to quit]

Now the installation of yii2-advanced template is completed, but still there is no database. So we want to create and use a database too. First of all we should install an RBAC module. Here I am using yii2-admin for RBAC. Take a look at the following steps:

Installation: RBAC system into your application

From the CMD window run the command composer require mdmsoft/yii2-admin "~2.0" for installing yii2-admin into your newly created application like:

C:\wamp\www\yii2-app>composer require mdmsoft/yii2-admin "~2.0"

It will be downloaded from git. After installation, the package (yii2-admin) will be located in the yii2-app/vendor/mdmsoft directory.

Then you should add some parameters to the configuration file yii2-app/common/config/main.php to access the yii2-admin and authManager as:

'modules' => [
    'admin' => [
        'class' => 'mdm\admin\Module',
        ...
    ]
    ...
],
...
'components' => [
    ...
    'authManager' => [
        'class' => 'yii\rbac\PhpManager', // or use 'yii\rbac\DbManager'
    ]
],

Create a database in MySql and configure your yii2-app/common/config/main-local.php file by adding the database credentials. Currently, there is no user table in your database. So you need to create user table for user management. For this yii2 provides an option for database migration. Run the command yii migrate --migrationPath=@mdm/admin/migrations in CMD for creating a proper user table for the user management. In CMD,

C:\wamp\www\yii2-app>yii migrate --migrationPath=@mdm/admin/migrations

The above command will create user and menu tables for your application.

Then change the user component properties in config file yii2-app/common/config/main.php as:

'components' => [
    ...
    'user' => [
        'identityClass' => 'mdm\admin\models\User',
        'loginUrl' => ['admin/user/login'],
    ]
]

Populate the user table by adding users. Use this link to register users to your application:
http://localhost/yii2-app/backend/web/index.php?r=admin/user/signup

You can use authManager class 'yii\rbac\DbManager' to authorize users using database. For that you should execute a database migration using the command yii migrate --migrationPath=@yii/rbac/migrations. Before that add 'class' => 'mdm\admin\models\User' and change the authManager class in the config file yii2-app/common/config/main.php like :

'components' => [
    ...
    'authManager' => [
        'class' => 'yii\rbac\DbManager', // or use 'yii\rbac\PhpManager'
    ],
    'user' => [
        'class' => 'mdm\admin\models\User',
        'identityClass' => 'mdm\admin\models\User',
        'loginUrl' => ['admin/user/login'],
    ]
]

and remove 'class' => 'mdm\admin\models\User' from the config file after migration. Execute the migration as:

C:\wamp\www\yii2-app>yii migrate --migrationPath=@yii/rbac/migrations

Don't forget to remove 'class' => 'mdm\admin\models\User' from the config file yii2-app/common/config/main.php.

You can use the following RBAC URLs to create and manage permissions/roles to the users:

http://localhost/yii2-app/backend/web/index.php?r=admin
http://localhost/yii2-app/backend/web/index.php?r=admin/route
http://localhost/yii2-app/backend/web/index.php?r=admin/permission
http://localhost/yii2-app/backend/web/index.php?r=admin/menu
http://localhost/yii2-app/backend/web/index.php?r=admin/role
http://localhost/yii2-app/backend/web/index.php?r=admin/assignment
http://localhost/yii2-app/backend/web/index.php?r=admin/user

Then you can create and manage routes/permissions/roles and assign them to the existing users using this interface. After setting the routes/permissions/roles, for checking whether a user has access to a particular action in a controller you need to add access control configuration parameters to the yii2-app/common/config/main.php file.

return [
    'modules' => [
        ....
    ],
    ....
    'as access' => [
        'class' => 'mdm\admin\components\AccessControl',
        'allowActions' => [
            'site/*',
            'admin/*',
        ]
    ]
]

You can add the public actions in allowActions array. The other actions will be checked by the AccessControl class for authorization.

Use the following github links for more instructions about yii2-advanced and yii2-admin:
https://github.com/yiisoft/yii2-app-advanced
https://github.com/mdmsoft/yii2-admin

Hope this article will help you to install yii2 and RBAC easily. Thanks for reading.

Happy coding :)

]]>
0
[wiki] A universal model attribute for its synthetic representation Sat, 20 Aug 2016 07:20:22 +0000 https://www.yiiframework.com/wiki/847/a-universal-model-attribute-for-its-synthetic-representation https://www.yiiframework.com/wiki/847/a-universal-model-attribute-for-its-synthetic-representation arodichevski arodichevski
  1. Example
  2. General considerations

It is convenient to use the same identification attribute, say info, in all of the active records of your application. It should be a virtual read-only attribute defined by a getter method, its label being the model name.

One can easily use the info attribute in breadcrumbs, detail views, grid views and other places. It will be $model->info instead of $model->id, $model->name or $model->name . ' ' . $model->lastname.

Example

Let us consider a hypothetical application treating states and cities having one-to-many relation.

Models
class State extends ActiveRecord
{
    // ...

    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'name' => 'State name',
            // ...
            'info' => 'State',
        ];
    }

    public function getInfo()
    {
        return $this->name;
    }
}

class City extends ActiveRecord
{
    // ...

    public function getInfo()
    {
        return $this->name;
    }

    public function getState()
    {
        return $this->hasOne(State::className(), ['id' => 'state_id']);
    }
}

The info attribute can be used throughout the application.

Title and breadcrumbs

This is the fragment of the city update view:

$this->title = 'Update ' . $model->info;
$this->params['breadcrumbs'][] = ['label' => 'States', 'url' => ['state/index']];
$this->params['breadcrumbs'][] = ['label' => $model->state->info, 'url' => ['state/view', 'id' => $model->state_id]];
$this->params['breadcrumbs'][] = ['label' => $model->info, 'url' => ['view', 'id' => $model->id]];
$this->params['breadcrumbs'][] = 'Update';

The page title "Update Seattle" is more informative then "Update City: 123" generated by the standard Gii template.

Cancel button

A cancel button in the state or the city view:

<?= Html::a(
    'Delete',
    ['delete', 'id' => $model->id],
    [
        'class' => 'btn btn-danger',
        'data' => [
            'confirm' => "Deleting {$model->info}. Are you sure?",
            'method' => 'post',
        ],
    ]
) ?>

This button, when pressed, asks: "Deleting Seattle. Are you sure?" instead of the standard "Are you sure you want to delete this item?".

DetailView attribute

A hyperlink in the detail view:

<?= DetailView::widget([
    'model' => $model,
    'attributes' => [
        // ...
        [
            'attribute' => 'state_id',
            'format' => 'raw',
            'value' => Html::a($model->state->info, ['state/view', 'id' => $model->state_id]),
        ],
    ],
]) ?>
GridView column

A column in a cities grid view:

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        // ...
        'state.info',
    ],
]); ?>

In this case the 'state.info' column label will be 'State', according to the City model definition.

The dropDownList

In the drop down list of the city's form:

<?= $form->field($model, 'state_id')
    ->dropDownList(
        ArrayHelper::map(State::find()->all(), 'id', 'info'),
        ['prompt' => 'Select one']
    )
?>

General considerations

Universality

The universal info attribute simplifies the application design because the developer should not remember the attribute names for every model used. Also, the info attribute label is always the model name, so the 'father.grandfather.info' column specification in the detail or grid views do not require the implicit label specification, like 'father.grandfather.info:text:My label'.

The info attribute is similar to the __toString() method used to convert any PHP object to the string.

The info attribute does not guarantee the unambiguous identification string, but gives a rapid information on the model in question.

Custom ActiveRecord class

If most of your models have the name attribute or similar data useful for identification, it is helpful to define you own ActiveRecord class:

class ActiveRecord extends \yii\db\ActiveRecord
{
    // ...

    /**
     * @return string Instantiated model name
     */
    public function getCalledClassName()
    {
        $reflectionClass = new \ReflectionClass(get_called_class());
        return $reflectionClass->getShortName();
    }

    /**
     * @return string Short description of the model
     */
    public function getInfo()
    {
        // Take the model name
        $m = $this->getCalledClassName();

        // Compound info in different cases
        if ($this->isNewRecord)
            $i = 'New ' . $m;
        elseif ($this->hasAttribute ('name') and trim($this->name))
            $i = trim($this->name);
        // ... other cases specific to your application
        else
            $i = $m . ' ' . $this->id;

        // Return the result
        return $i;
    }
}
Override getInfo()

In some models you can override the default getInfo() method defined in your ActiveRecord class. For example, the active record of a person can be identified by the first and the last name:

class Person extends ActiveRecord
{
    // ...

    public function attributeLabels()
    {
        return [
            // ...
            'info' => 'Person',
        ];
    }

    public function getInfo()
    {
        // The first and the last names combined
        $i = trim(trim($this->name) . ' ' . trim($this->lastname)]);

        // If empty, take the default value
        if (! $i)
            $i = parent::getInfo();

        // Return the result
        return $i;
    }
}

The info value is never empty. Some possible examples of its values:

  1. Jane Doe
  2. Jane
  3. Doe
  4. Person 123
  5. New Person

The case 1 is when there are both the first and the last names evaluated. The cases 2 and 3 are when there is only the first or only the last name evaluated, respectively. The case 4 is when the first and the last names are both empty. The last case is for a new record not yet saved to the database.

Search ActiveRecord class

The info attribute should be defined as not searchable in the search class:

class PersonSearch extends Person
{
    // ...
    public function rules()
    {
        return [
            // ...
            [['!info'], 'safe', 'on' => '*']
        ];
    }
}
Gii templates

One can include the above code examples in the customized Gii model and CRUD templates.

]]>
0
[wiki] Yii2: How to create/develop a new extension using Composer locally without version control or Git Fri, 12 Aug 2016 21:59:41 +0000 https://www.yiiframework.com/wiki/846/yii2-how-to-createdevelop-a-new-extension-using-composer-locally-without-version-control-or-git https://www.yiiframework.com/wiki/846/yii2-how-to-createdevelop-a-new-extension-using-composer-locally-without-version-control-or-git wadeshuler wadeshuler

Using a version control system, like Git, is nice. However, when building an extension from scratch and loading it via Composer, it adds a lot of pain in the butt steps. You have to commit your changes, update composer to pull them over, then notice there is an error, fix, commit, update. repeat.. I don't want all my baby steps under Git. Sure, I could edit my commit history, but c'mon. Just let me code! I will put it under version control once I get a baseline created. This guide will show you how to setup your composer.json to load a local directory (everything inside, live). You make a change, save the file, refresh the page, boom.

What about after you have a release of your extension, but you want to work on it to add a new feature or fix a bug? It needs to be useable in Yii2 while you work on it. So again, we don't need all the extra steps. Using the instructions in this guide, you will be able to edit your composer.json to load the files live via a symbolic link. You won't have to commit or update to see your changes in your Yii app!

This is the best way to develop new extensions for Yii! It is also the best way to work on your already existing extensions to fix bugs or add new features!

First, lets create a directory for our new extension. I am on a Mac and use XAMPP, so your paths may vary. I don't want to put my extension inside my Yii2 app because it is separate, meant to be pushed to Git and Packagist, and shared with the world, and used later. It is independent, I am just using my Yii2 app as a testing ground to build it, even if I am planning on using it inside the app for real.

cd /Applications/XAMPP/xamppfiles/htdocs
mkdir yii2-myextension
cd yii2-myextension
composer init

Follow the interactive wizard. I use Atom, and I would open a new Atom editor window, then "File > Add Project Folder" and select "yii2-myextension" to open the whole directory to work in. Now, we will only have "composer.json" in here so far. Open it.

You will notice that "init" automatically created a basic composer file. Here is mine, excluding keywords, description, etc. because those don't really matter.

{
    "name": "wadeshuler/yii2-myextension",
    "type": "yii2-extension",
    "minimum-stability": "dev",
    "autoload": {
        "psr-4": {
            "wadeshuler\\myextension\\": ""
        }
    }
}

Name: The name is /yii2-. I use my GitHub username (WadeShuler), all lowercase and no spaces (wadeshuler). It would help if you create a GitHub account first, and also create a Packagist account. Packagist uses your GitHub username :) Keep those 3 in sync and you will reduce issues. You should also prefix your extensions with "yii2-". It is a Yii standard practice, helps others know it is for Yii2 and not Yii1.

Type: You must use "yii2-extension" for the type, this tells Yii to load it into your extensions file for internal use. Click here to read more.

Min Stability: it is important to use "dev" here during testing. We have no version control (yet) and we will force our main Yii2 composer.json to accept a "dev" dependency even though Yii2 requires stable, by using "@dev" for the repo (shown later).

Autoload: I use PSR-4 and you probably should too. Most Yii2 packages I have encountered are PRS4. I feel it is better an easier, I don't just follow suit to be a sheep :P Notice how it has my vendor name, "wadeshuler" then double backslashes. These are important. If you don't know about the double backslashes, then read here. It then has the name of my extension. However, there is no "yii2" in it. This is actually the namespace we are going to use, we can call it whatever we want, so we can omit the "yii2-" to be cleaner and easier to write later. This is the namespace that defines where your extension is located. Here in Composer, we are saying "wadeshuler/whateveriwant" is going to be our namespace, and it is located "" <-- root dir of the loaded extension. You could do "wadeshuler\myextension\": "/src" <-- in your extensions src directory if you want to put everything in a "src" dir and just have your "README", "LICENSE" and "composer.json" in your extensions root dir.

Ok, so here, your Yii2 extension is ready for use in Composer. We will add files later. Right now, there is nothing but "composer.json" in our directory.

We need to load our extension into our Yii2 app. Open your Yii2 app's "composer.json" file, lets add our extension.

    "require-dev": {
        "wadeshuler/yii2-myextension": "@dev"
    },
    "repositories": [
        {
            "type": "path",
            "url": "/Applications/XAMPP/xamppfiles/htdocs/yii2-myextension"
        }
    ],

You probably don't have a "repositories" section, so add it. Notice we use "path" for the type, this does not require any version control :) For the url, I use the full path to the extension I am currently working on. This will actually create a symbolic link to the directory, which is key for live editing! I added my extension to the "require-dev" section, because it is development. Just in case this was pushed to the server, I don't want to break anything. When it's all done and on Packagist, I would put it where it belongs and remove the entry in "repositories" so it loads from Packagist and not my local computer.

Now we are ready to run: ~~~ composer update ~~~

If everything is correct, you should see Composer load your library when watching your terminal output. Open your Yii2 app in your editor and view the "vendor" directory, look for your namespace dir (wadeshuler for me), then under it you should see a directory for your extension. Now, it is empty. If it loaded fine, you are ready to start building your extension. All changes are live in your main Yii app so you can test while coding! No committing, no updating. Just edit, save, refresh!!!

When you are done and your extension is perfect, you can then put it under version control, push it to GitHub and Packagist. Then you remove the "repositories" section so it no longer links to your local directory, and edit the "require-dev" just like adding anything else from Packagist. How to add your Packagist package is beyond the scope of this tutorial. However, the gist is, you must make a "release" in GitHub in order for Packagist to work.

Ok, so now your extension is great, however there is a bug you need to fix and you want to add a new feature.. Here is what I would do.

We don't need to commit or update for this either. Revert your "composer.json" back to how I showed above, so you are "live editing" again. If you lost your project, you could "git clone" it back into your "htdocs". You can combine live editing and with your GitHub workflow. You can create a branch, live edit your files, and commit when ready. This is possible because when you switch the branch, the files are actually swapped instantly. So the file has your code, even if you haven't committed it yet! We aren't relying on any VCS, just the files like the good ole days.

Once you fixed your repo and have committed the changes, push it back to GitHub.

]]>
0