Live News for Yii Framework News, fresh extensions and wiki articles about Yii framework. Sun, 22 Sep 2019 05:45:36 +0000 Zend_Feed_Writer 2 (http://framework.zend.com) https://www.yiiframework.com/ [wiki] Yii v2 snippet guide Sat, 21 Sep 2019 06:44:05 +0000 https://www.yiiframework.com/wiki/2552/yii-v2-snippet-guide https://www.yiiframework.com/wiki/2552/yii-v2-snippet-guide rackycz rackycz
  1. Intro
  2. Prerequisities
  3. Yii demo app + GitLab
  4. User management + DB creation + login via DB
  5. i18n translations
  6. Switching languages + session + dropdown in the top menu
  7. Access rights

Intro

Hi all!

This snippet guide continues in my series of simple Yii tutorials. Previous two contain basic info about MVC concept so read them as well, but they are meant for Yii v1. I started with them cca 8 years ago:

... and today I am beginning with Yii 2 so I will also gather my snippets and publish them here so we all can quickly setup the yii-basic-demo just by copying and pasting. This is my goal - to show how-to without long descriptions.

... technologies should not require users to study them deeply in order to run basic functionalities. Ordinary things should be copied and pasted so that one is happy that it works and thus motivated to study more ...

I have 4 years of experiences with Yii 1, but I havent used it for almost 5 years so many things in Yii 2 are new for me again. Plus I was suprised that the Yii 2 demo application does not contain some basic functionalities (like login via DB, translations etc) which must be implemented in the most of web projects so I will focus on them. Plus I will talk about GitLab.

If you find any problems in my snippets, let me know, please.

Prerequisities

Skip this paragraph if you know how to run your Yii demo project...

I work with Win10 + XAMPP Server so I will expect this configuration. Do not forget to start the server and enable Apache + MySQL in the dialog. Then test that following 2 URLs work for you

You should also download the Yii basic demo application and place it into the htdocs folder. In my case it is here:

  • C:\xampp\htdocs

And your index.php should be here:

  • C:\xampp\htdocs\basic\web\index.php

If you set thing correcly up, following URL will open your demo application. Now it will probably throw an exception:

The Exception is removed by enterinng any text into attribute 'cookieValidationKey' in file:

  • C:\xampp\htdocs\basic\config\web.php

Dont forget to connect Yii to the DB. It is done in file:

  • C:\xampp\htdocs\basic\config\db.php

... but it should work out-of-the-box if you use DB name "yii2basic" which is also used in examples below ...

Yii demo app + GitLab

Once I know more about GitLab I will add some info ... for example automatical copying from GitLab to your target web space.

Once you download and run the basic app, I recommend to push it into GitLab. You will probably need a SSH certificate which can be generated like this using PuTTYgen. When I work with Git I use TortoiseGIT which integrates all git functionalities into the context menu in Windows File Explorer.

First go to GitLab web and create a new project. Then you might need to fight a bit, because the process of connecting your PC to GIT seems to be quite complicated. At least for me.

Once things work, just create an empty folder, right click it and select Git Clone. Enter your git path, best is this format:

When cloned, copy the content of the "basic" folder into the new empty git-folder and push everything except for folder "vendor". (It contains 75MB and 7000 files so you dont want to have it in GIT)

Then you can start to modify you project, for example based on this "tutorial".

User management + DB creation + login via DB

To create DB with users, use following command. I recommend charset utf8_unicode_ci (or utf8mb4_unicode_ci) as it allows you to use more international characters.

CREATE DATABASE IF NOT EXISTS `yii2basic` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

CREATE TABLE IF NOT EXISTS `user` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(45) NOT NULL,
  `password` VARCHAR(60) NOT NULL,
  `email`    VARCHAR(60) NOT NULL,
  `authKey`  VARCHAR(60),
  PRIMARY KEY (`id`))
ENGINE = InnoDB;

INSERT INTO `user` (`id`, `username`, `password`, `email`, `authKey`) VALUES (NULL, 'user01', '0497fe4d674fe37194a6fcb08913e596ef6a307f', 'user01@gmail.com', NULL);

If you must use MyISAM instead of InnoDB, just change the word InnoDB into MYISAM.

Then replace existing model User with following snippet

  • The model was generated by Gii and originally had 3 methods: tableName(), rules(), attributeLabels()
  • In order to use the DB for login, we needed to implement IdentityInterface which requires 5 new methods.
  • Plus we add 2 methods because of the default LoginForm and 1 validator.
<?php

namespace app\models;

use Yii;

class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface {

    // When user detail is being edited we will only modify attribute password_new
    // Why? We dont want to load password-hash from DB and display it to the user
    // We only want him to see empty field and if it is filled in, password is changed on background
    public $password_new;
    public $password_new_repeat;

    // Use this scenario in UserController->actionCreate() right after: $model = new User() like this:
    // $model->scenario = User::SCENARIO_CREATE;
    // This will force the user to enter the password when new user is created
    // When user is edited, new password is not needed
    const SCENARIO_CREATE = "user-create";

    // ----- Default 3 model-methods by GII:

    public static function tableName() {
        return 'user';
    }

    public function rules() {
        return [
            [['username', 'email'], 'required'],
            [['password_new_repeat', 'password_new'], 'required', "on" => self::SCENARIO_CREATE],
            [['username', 'email'], 'string', 'max' => 45],
            ['email', 'email'],
            [['password', 'authKey'], 'string', 'max' => 60],
            [['password', 'password_new_repeat', 'password_new'], 'safe'],
            ['password_new_repeat', 'compare', 'operator' => '==', 'compareAttribute' => 'password_new'],
            ['password_new_repeat', 'setPasswordWhenChanged'],
        ];
    }

    public function attributeLabels() {
        return [
            'id' => Yii::t('app', 'ID'),
            'username' => Yii::t('app', 'Username'),
            'password' => Yii::t('app', 'Password'),
            'password_new' => Yii::t('app', 'New password'),
            'password_new_repeat' => Yii::t('app', 'Repeat new password'),
            'authKey' => Yii::t('app', 'Auth Key'),
            'email' => Yii::t('app', 'Email'),
        ];
    }

    // ----- Password validator

    public function setPasswordWhenChanged($attribute_name, $params) {

        if (trim($this->password_new_repeat) === "") {
            return true;
        }

        if ($this->password_new_repeat === $this->password_new) {
            $this->password = sha1($this->password_new_repeat);
        }

        return true;
    }

    // ----- IdentityInterface methods:

    public static function findIdentity($id) {
        return static::findOne($id);
    }

    public static function findIdentityByAccessToken($token, $type = null) {
        return static::findOne(['access_token' => $token]);
    }

    public function getId() {
        return $this->id;
    }

    public function getAuthKey() {
        return $this->authKey;
    }

    public function validateAuthKey($authKey) {
        return $this->authKey === $authKey;
    }

    // ----- Because of default LoginForm:

    public static function findByUsername($username) {
        return static::findOne(['username' => $username]);
    }

    public function validatePassword($password) {
        return $this->password === sha1($password);
    }

}

Validators vs JavaScript:

  • There are 2 types of validators. All of them are used in method rules, but as you can see, the validator setPasswordWhenChanged is my custom validator and needs a special method. (I just abused a validator to set the password value, no real validation happens inside)
  • If a validator does not need this special method, it is automatically converted into JavaScript and is used on the web page when you are typing.
  • If a validator needs the method, it cannot be converted into JavaScript so the rule is checked only in the moment when user sends the form to the server - after successful JavaScript validation.

Now you can also create CRUD using GII:

CRUD = Create Read Update Delete = views and controller. On the GII page enter following values:

  • Model Class = app\models\User
  • Search Model Class = app\models\UserSearch
  • Controller Class = app\controllers\UserController
  • View Path can be empty or you can set: views\user
  • Again enable i18n

And then you can edit users on this URL: http://localhost/basic/web/index.php?r=user ... but it is not all. You have to modify the view-files so that correct input fields are displayed!

Open folder views\user and do following:

  • _form.php - rename input password to password_new then duplicate it and rename to password_new_repeat. Remove authKey.
  • _search.php - remove password and authKey.
  • index.php - remove password and authKey.
  • view.php - remove password and authKey.

Plus do not forget to use the new scenario in UserController->actionCreate() like this:

public function actionCreate()
{
  $model = new User();
  $model->scenario = User::SCENARIO_CREATE; // the new scenario!
  // ...

i18n translations

Translations are fairly simple, but I probably didnt read manuals carefully so it took me some time.

First create following folders and file.

  • "C:\xampp\htdocs\basic\messages\cs-CZ\app.php"

(Note that cs-CZ is for Czech Lanuage. For German you should use de-DE etc. Use any other language if you want.)

The idea behind is that in the code ther are used only English texts and if you want to change from English to some other language this file will be used.

Now go to file config/web.php, find section "components" and paste this code:

    'components' => [
        'i18n' => [
          'translations' => [
            '*' => [
              'class' => 'yii\i18n\PhpMessageSource',
              'basePath' => '@app/messages',
              'sourceLanguage' => 'en-US',
              'fileMap' => [
                'app' => 'app.php'
              ],
            ],
          ],
        ], // end of 'i18n'

        // ... other configurations

    ], // end of 'components'
    

Explanation of the asterisk * can be found in article https://www.yiiframework.com/doc/guide/2.0/en/tutorial-i18n

You surely saw that in views and models there are texts saved like this:

Yii::t('app', 'New password'),

It means that this text belongs to category "app" and its English version (and also its ID) is "New password". So this ID will be searched in the file you just created. In my case it was the Czech file:

  • "C:\xampp\htdocs\basic\messages\cs-CZ\app.php"

Therefore open the file and paste there following code:

<?php
return [
    'New password' => 'Nové heslo',
];
?>

Now you can open the page for adding a new user and you will see than so far nothing changed :-)

We must change the language ... For now let's do it in a primitive and permanent way again in file config/web.php

$config = [
    // use your language
    // also accessible via Yii::$app->language
    'language' => 'cs-CZ',
    
    // This attribute is not necessary.
    // en-US is default value
    'sourceLanguage' => 'en-US',
    
    // ... other configs

Switching languages + session + dropdown in the top menu

First lets add to file config/params.php attributes with list of supported languages:

<?php
return [
    // ...
    'allowedLanguages' => [
        'en-US' => "English",
        'cs-CZ' => "Česky",
    ],
    'langSwitchUrl' => '/site/set-lang',
];

This list can be displayed in the main menu. Edit file:

  • C:\xampp\htdocs\basic\views\layouts\main.php

And above the Nav::widget add few rows:

    $listOfLanguages = [];
    $langSwitchUrl = Yii::$app->params["langSwitchUrl"];
    foreach (Yii::$app->params["allowedLanguages"] as $langId => $langName) {
        $listOfLanguages[] = ['label' => Yii::t('app', $langName), 'url' => [$langSwitchUrl, 'langID' => $langId]];
    }

and then add one item into Nav::widge

    echo Nav::widget([
        // ...
        'items' => [
            // ...
            ['label' => Yii::t('app', 'Language'),'items' => $listOfLanguages],
            // ...

Now in the top-right corner you can see a new drop-down-list with list of 2 languages. If one is selected, action "site/setLang" is used so we have to create it in SiteController.

Note that this approach will always redirect user to the new action and his work will be lost. Nevertheless this approach is very simple so I am using it in small projects. More complex projects may require an ajax call when language is changed and then updating texts using javascript so reload is not needed and user's work is preserved. But I expect that when someone opens the web, he/she sets the language immediately and then there is no need for further changes.

The setLang action looks like this:

    public function actionSetLang($langID = "") {
        $allowedLanguages = Yii::$app->params["allowedLanguages"];
        $langID = trim($langID);
        if ($langID !== "" && array_key_exists($langID, $allowedLanguages)) {
            Yii::$app->session->set('langID', $langID);
        }
        return $this->redirect(['site/index']);
    }

As you can see when the language is changed, redirection to site/index happens. Also mind that we are not modifying the attribute from config/web.php using Yii::$app->language, but we are saving the value into the session. The reason is that PHP deletes memory after every click, only session is kept.

We then can use the langID-value in other controllers using new method beforeAction:

    public function beforeAction($action) {

        if (!parent::beforeAction($action)) {
            return false;
        }

        Yii::$app->language = Yii::$app->session->get('langID');

        return true;
    }

.. or you can create one parent-controller named for example BaseController. All other controllers will extend it.

<?php

namespace app\controllers;

use Yii;
use yii\web\Controller;

class BaseController extends Controller {

    public function beforeAction($action) {

        if (!parent::beforeAction($action)) {
            return false;
        }

        Yii::$app->language = Yii::$app->session->get('langID');

        return true;
    }

}

As you can see in the snippet above, other controllers must contain row "use app\controllers\BaseController" + "extends BaseController"

Access rights

... text ...

]]>
0
[extension] neoacevedo/yii2-storage Thu, 19 Sep 2019 20:16:14 +0000 https://www.yiiframework.com/extension/neoacevedo/yii2-storage https://www.yiiframework.com/extension/neoacevedo/yii2-storage NestorAcevedo NestorAcevedo

Yii2 Storage

  1. Instalación
  2. Uso

Latest Stable Version Total Downloads Latest Unstable Version License Monthly Downloads Daily Downloads

Gestión de almacenamiento para Yii2.

Instalación

La forma preferida de instalar esta extensión es a través de composer.

Luego ejecute

php composer.phar require --prefer-dist neoacevedo/yii2-storage

o agregue

"neoacevedo/yii2-storage": "^18.08"

a la sección require de su archivo composer.json.

Uso

Una vez que la extensión está instalada, configure las credenciales para el servicio de almacenamiento en el archivo de configuración de su aplicación Yii :

<?php

'components' => [
	/**
	 * Amazon S3
	 */ 
	'storageAWS' => [
	    'class' => 'neoacevedo\yii2\Storage',
	    'service' => 's3',
	    'config' => [
	        'key' => 'YOUR_IAM_ACCESS_KEY',
	        'secret' => 'YOUR_IAM__SECRET_ACCESS_KEY',
	        'bucket' => 'your-bucket',
	        'region' => 'your-region',
	        'extensions' => 'pdf, jpg, jpeg, gif, png, bmp'
	    ],
	    'prefix' => '', // ruta al directorio de imágenes. Ej: images/ (Opcional)
	]


	/**
	 * Azure Storage Blob
	 */
	'storageAzure' => [
	    'class' => 'neoacevedo\yii2\Storage',
	    'service' => 'azure',
	    'config' => [
	        'accountName' => 'ACCOUNT_NAME',
	        'accountKey' => 'ACCOUNT_KEY',
	        'container' => 'your-container',
	        'extensions' => 'pdf, jpg, jpeg, gif, png, bmp'
	    ],
	    'prefix' => '' // ruta al directorio de imágenes. Ej: images/ (Opcional)
	]

	/**
	 * Google Storage Cloud
	 */
	'storageGoogle' => [
	    'class' => 'neoacevedo\yii2\Storage',
	    'service' => 'gsc',
	    'config' => [
	        'projectId' => 'YOUR_PROJECT_ID',
	        'bucket' => 'your-bucket'
	        'keyFile' => '', // Contenido del archivo JSON generado en la consola de Google
	        'extensions' => 'pdf, jpg, jpeg, gif, png, bmp'
	    ],
	    'prefix' => '', // ruta al directorio de imágenes. Ej: images/ (Opcional)
	]

	/**
	 * Almacenamiento local
	 */ 
	'storageLocal' => [
	    'class' => 'neoacevedo\yii2\Storage',
	    'service' => 'local',
	    'config' => [
	        'baseUrl' => Yii::$app->request->hostInfo, // ej: http://example.com/
	        'directory' => '@webroot/web/uploads/', // reemplace @webroot por @frontend o @backend según sea el caso. La ruta debe terminar con una barra diagonal
	        'extensions' => 'pdf, jpg, jpeg, gif, png, bmp'
	    ],
	    'prefix' => '', // ruta al directorio de imágenes. Ej: images/ (Opcional) (Opcional)
]

Ahora puede llamarlo desde su aplicación :

/**
 * Sube el archivo de imagen.
 * @param yii\web\UploadedFile $imageFile
 * @return boolean
 */
public function upload($imageFile)
{
    if (null !== $imageFile) {
        Yii::$app->storage->uploadedFile = $imageFile;
        return Yii::$app->storage->save();
    } else {
        return false;
    }
}

...
// obtener la URL generada
echo Yii::$app->storage->getUrl(Yii::$app->storage->prefix.$model->image_file); 

O simplemente en su código :

<?php 
use neoacevedo\yii2\Storage;

public function upload()
{
	$storage = new Storage([
		'service' => Storage::AWS_S3,
		'config' => [
			'key' => 'YOUR_IAM_ACCESS_KEY',
			'secret' => 'YOUR_IAM_SECRET_ACCESS_KEY',
			'bucket' => 'your-bucket',
			'region' => 'your-region',
			'extensions' => 'pdf, jpg, jpeg, gif, png, bmp'
		],
		'prefix' => '' // opcional
	]);
	
	$storage->uploadedFile = \yii\web\UploadedFile::getInstanceByName("file");
	return $storage->save();
}

Puede usar el modelo del componente en su formulario de las siguientes maneras en su controlador:

...
// Constructor de clase
	$storage = new Storage([
		'service' => Storage::AWS_S3,
		'config' => [
			'key' => 'YOUR_IAM_ACCESS_KEY',
			'secret' => 'YOUR_IAM_SECRET_ACCESS_KEY',
			'bucket' => 'your-bucket',
			'region' => 'your-region',
			'extensions' => 'pdf, jpg, jpeg, gif, png, bmp'
		],
		'prefix' => '' // opcional
	]);
	return $this->render('create', [
                'model' => $model,
                'fileModel' => $storage->getModel()
    ]);	
...
// Como componente
	return $this->render('create', [
                'model' => $model,
                'fileModel' => Yii::$app->storage->getModel()
    ]);
...
// Usando el modelo de manera directa
	return $this->render('create', [
                'model' => $model,
                'fileModel' => new neoacevedo\yii2\storage\models\FileManager()
    ]);

Dentro de la vista:

<?= $form->field($fileModel, 'uploadedFile')->fileInput() ?>
]]>
0
[news] Yii 2.0.27 Wed, 18 Sep 2019 19:15:22 +0000 https://www.yiiframework.com/news/249/yii-2-0-27 https://www.yiiframework.com/news/249/yii-2-0-27 samdark samdark

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

Version 2.0.27 is a minor release of Yii 2.0. This release includes bug fixes accumulated since last release and a two enhancements from old pull requests:

  • When using incorrect alias or option in console it now lists correct ones.
  • appendTimestamp support was added to View methods registerCssFile() and registerJsFile().

Thanks to all Yii community members who contribute to the framework, translators who keep documentation translations up to date and community members who answer questions at forums.

There are many active Yii communities so if you need help or want to share your experience, feel free to join them.

A complete list of changes can be found in the CHANGELOG.

]]>
0
[news] Debug extension 2.1.9 released Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/news/248/debug-extension-2-1-9-released https://www.yiiframework.com/news/248/debug-extension-2-1-9-released samdark samdark

Debug extension version 2.1.9 was released fixing a bug in "logs" panel "since previous" column values calculation.

See the CHANGELOG for details.

]]>
0
[extension] dropdown-for-gridview Wed, 18 Sep 2019 07:41:48 +0000 https://www.yiiframework.com/extension/dropdown-for-gridview https://www.yiiframework.com/extension/dropdown-for-gridview Jay_69 Jay_69
  1. Requirements
  2. Installation
  3. Usage

In place editable dropdown for Yii2 GridView This is extansion of DataColumn of Yii2. Allows to edit data of integer type directly in GridView column.

Requirements

Yii 2.0

Installation

Create folder "jz" in "vendor" in your project. Place JZDropDownColumn.php in "jz" folder. Or any other reachable one. Place jzgridviewcolumn.js in you JavaScript folder. Place jzgridviewcolumn.css in your CSS folder. Make necessary changes to AppAsset.php.

Usage

//Example for usage in GridView


Pjax::begin(['id' => 'pjax_id_1', 'options'=> ['class'=>'pjax', 'loader'=>'loader_id_1', 'neverTimeout'=>true]]);

    echo GridView::widget([

        'dataProvider' => $dp,

        'filterModel' => $model,

        'options'=>['class'=>'grid-view','id'=>'grid_id_1'],

        'summaryOptions'=>['style'=>'text-align:right;'],

        'columns' => [

            [
		      'class' => 'vendor\jz\JZDropDownColumn',
                'className' => 'Payment',
                'attribute' => 'payment_method',
                'editable' => true,
                'list' => $model::$paymentMethodArr,
		      'editUrl' => Url::to(['payment/intedit']),
		      'emptyLabel' => Yii::t('msg','Click me to change'),
		      'denyLabel' => Yii::t('msg','CANCEL'),
		      'loaderPath' => Yii::getAlias('@jzCssImgWeb').'/img_loader.gif',
                'headerOptions' => ['style'=>'width:200px; text-align:center;'],
            ],

        ],

    ]); 

Pjax::end();

//Example of action for edit attribute


    public function actionIntedit(){		
        if(isset($_GET['data'])){
            $json = json_decode($_GET['data']);
            if(isset($json->class) && isset($json->id) && isset($json->attribute) && isset($json->value)){
                $className = $json->class;
                if($className == 'Payment'){
                    $model = Payment::findOne(intval($json->id));
                    if(isset($model)){
                        $attribute = $json->attribute;
                        $model->$attribute = intval($json->value);//variable variable!!!
                        if($model->save()){
                            return json_encode(['msg'=>1,'val'=>$model->$attribute]);
                        } else {return json_encode(['msg'=>0,'val'=>$this->firstErrorMessage($model)]);}
                    } else {return json_encode(['msg'=>0,'val'=>'No model found.']);}
                }
            } else {return json_encode(['msg'=>0,'val'=>'No correct data set provided.']);}
        } else {return json_encode(['msg'=>0,'val'=>'No data provided.']);}
    }
    
]]>
0
[extension] crazyteea/yii2-beautyfiles Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/crazyteea/yii2-beautyfiles https://www.yiiframework.com/extension/crazyteea/yii2-beautyfiles CrazyTeea CrazyTeea

yii2-beautyfiles

удобная работа с файлами

]]>
0
[wiki] Change default date format in Oracle Fri, 20 Sep 2019 06:15:43 +0000 https://www.yiiframework.com/wiki/2551/change-default-date-format-in-oracle https://www.yiiframework.com/wiki/2551/change-default-date-format-in-oracle lenovo7 lenovo7

Default date format in Oracle is DD-MON-RR (25-JAN-18). With that output, we can't using date formatting.

Too solve this issue, we must change date format oracle like date commonly using

ALTER SESSION SET NLS_DATE_FORMAT = ...

Add this script inside your database connection file

<?php

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'oci:host=127.0.0.1:1521/XE',
    'username' => 'your_username',
    'password' => 'your_password',
    'charset' => 'utf8',

    // Schema cache options (for production environment)
    //'enableSchemaCache' => true,
    //'schemaCacheDuration' => 60,
    //'schemaCache' => 'cache',

    'on afterOpen' => function($event) {
        // $event->sender refers to the DB connection
        $event->sender->createCommand("ALTER SESSION SET NLS_DATE_FORMAT='DD-MM-YYYY hh24:mi:ss'")->execute();
    }    
];
]]>
0
[extension] execut/yii2-javascript-handler Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/execut/yii2-javascript-handler https://www.yiiframework.com/extension/execut/yii2-javascript-handler eXeCUT eXeCUT

yii2-javascript-handler

Javascript error handler for Yii2

Install

Either run

$ php composer.phar require execut/yii2-javascript-handler "dev-master"

or add

"execut/yii2-javascript-handler": "dev-master"

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

Configuration

Add module inside web application config: `php return [

'modules' => [
    'javascriptHandler' => [
        'class' => Module::class,
    ]
],

]; `

Render widget inside your application layout: `php echo \execut\javascriptHandler\JavascriptHandlerWidget::widget([

'clientOptions' => [
    'test' => true,// delete this line for stopping sending a test exception
],

]); `

As a result, all javascript exceptions will throw php exceptions, that will be handled via yii2 error handler

]]>
0
[extension] solutosoft/yii-audit-record Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/solutosoft/yii-audit-record https://www.yiiframework.com/extension/solutosoft/yii-audit-record leandrogehlen leandrogehlen

Yii Audit Record

This extension provides support for store active record changes for Yii2.

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

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist solutosoft/yii-audit-record

or add

"solutosoft/yii-audit-record": "*"
]]>
0
[extension] shahimian/yii2-dategj Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/shahimian/yii2-dategj https://www.yiiframework.com/extension/shahimian/yii2-dategj shahimian shahimian

Date GJ

  1. Installation
  2. Usage
  3. Method Details

it convert Gregorian date to Jalali calendar one.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist shahimian/yii2-dategj "*"

or add

"shahimian/yii2-dategj": "*"

to the require section of your composer.json file.

Usage

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

<?= $dt = \Yii::createObject([
    'class' => \shahimian\dategj\DateGJ::className(),
    'datetime' => '2019-09-08 11:56', /* format YYYY-MM-DD HH:MM */
]); ?>

You can set another value in $dt->datetime later if you want.

Method Details

You use various methods in this class presented in list below:

public string gj()

gets $dt->datetime it formats YYYY-MM-DD HH:MM as Gregorian date and converting that same format as Jalali date.

public Array convertor()

gets argument with upper format and converting as array. it contains 3 cells for year, month and day.

public integer year()

gets argument and returning converted year number.

public integer month()

gets argument and returning converted month number.

public integer day()

gets argument and returning converted day number.

public string month_name($month : integer)

gets month number and returning month name as farsi language.

public string full_date()

return full date contains year, month and day as farsi language.

public string weekday()

return a day of the week as farsi language.

public Array dateSegment()

return Array that is year, month and day for its indeces respectively.

]]>
0
[extension] dmitrybtn/yii2-yimp Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/dmitrybtn/yii2-yimp https://www.yiiframework.com/extension/dmitrybtn/yii2-yimp dmitrybtn dmitrybtn

YIMP - Панель управления для Yii 2 на Bootstrap 4

Концепция

YIMP - это панель управления, предназначенная для быстрого создания пользовательского интерфейса. Это не готовая админка, не CMS и даже не CMF. Код представлений нужно писать самостоятельно или с использованием Gii (шаблоны прилагаются).

YIMP представляет собой лейаут, адаптированный для мобильных устройств и включающий в себя заголовок приложения, заголовок страницы, хлебные крошки, три меню (верхнее, левое и правое) а также виджеты в боковых панелях. Эти свойства настраиваются в контроллерах и передаются в лейаут через специальный объект - навигатор.

Полезные ссылки: Live demo, API documentation.

Установка через Composer

В настоящее время разработка еще не завершена. Версия 1.0 должна выйти до конца сентября 2019 года. Если Вы хотите попробовать YIMP, установите через Composer версию dev-master. Для этого:

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

php composer.phar require dmitrybtn/yii2-yimp:dev-master

или добавьте

"dmitrybtn/yii2-yimp": "dev-master"

в секцию require вашего composer.json.

Быстрый старт
Подключение лейаута

Лейаут хранится в папке vendor/dmitrybtn/yii2-yimp/views/layout. Для подключения лейаута рекомендуется скопировать его код в приложение. Тем не менее, в простейших случаях можно подключить лейаут из пакета, для этого в настройках приложения нужно указать:

'layout' => '@dmitrybtn/yimp/views/layout',
Подключение навигатора

В приложении необходимо определить класс, унаследованный от \dmitrybtn\yimp\Navigator. Этот класс будет использоваться для передачи данных из контроллера в лейаут. Он включает в себя набор свойств (полный перечень лучше посмотреть в API документации), которые задаются в контроллере и выводятся в лейауте. Унаследовав этот класс в своем приложении, рекомендуется сразу настроить меню, которые не будут зависеть от конкретного действия. Например, так:

namespace app\components;

class Navigator extends \dmitrybtn\yimp\Navigator
{
    public function init()
    {
        parent::init();

        $this->menuLeft = [
            ['label' => 'Main menu'],
            ['label' => 'About', 'url' => ['/site/about']],
        ];
    }
}

В контроллере нужно определить свойство nav, являющееся объектом класса Navigator. В действиях контроллера нужно настроить своство nav желаемым образом. Например, так:

class SiteController extends \yii\web\Controller
{
    public $nav;

    public function init()
    {
        parent::init();

        $this->nav = new Navigator();
    }

    public function actionAbout()
    {
        $this->nav->title = 'About';

        ...
    }
}
Подключение Gii

В состав YIMP входят шаблоны для CRUD и контроллеров. Для их подключения в настройках приложения нужно указать:

    'modules' => [
        ...
        'gii' => [
             'class' => 'yii\gii\Module',
             'allowedIPs' => ['127.0.0.1', '::1'],
             'generators' => [
                 'crud' => [
                     'class' => 'yii\gii\generators\crud\Generator',
                     'templates' => [
                         'yimp' => '@dmitrybtn/yimp/gii/crud'
                     ]
                 ],
                 'controller' => [
                     'class' => 'yii\gii\generators\controller\Generator',
                     'templates' => [
                         'yimp' => '@dmitrybtn/yimp/gii/controller'
                     ]
                 ]
             ],
        ...
    ]

Эти шаблоны переопределяют шаблоны, используемые Gii по умолчанию, причем изменения были по возможности минимальными. При необходимости, вы можете переопределить эти шаблоны согласно документации на Gii.

Подключение ErrorAction

В состав YIMP входит ErrorAction, который можно подключить согласно соответствующему разделу документации на Yii.

Рекомендации

Левое меню рекомендуется использовать как главное меню приложения. Верхнее меню - для опций текущего пользователя (логин, логаут, настройки профиля). Правое меню - для опций текущего действия (например, для действия View там будут пункты Update и Delete). Левое и верхнее меню рекомендуется настроить в вашей реализации класса Navigator, а правое меню - в коде действий.

Заголовки действий и хлебные крошки рекомендуется определять через статические методы контроллеров. Например, так:

class OrderController extends \yii\web\Controller
{
    public $nav;

    public function init()
    {
        parent::init();

        $this->nav = new Navigator();
    }

    public static function titleIndex()
    {
        return 'Заказы';
    }

    public static function titleView($order)
    {
        return 'Заказ № ' . $order->id;
    }

    public static function crumbsToIndex()
    {
        return [
            ['label' => static::titleIndex(), 'url' => ['index']]
        ];
    }

    public function actionIndex()
    {
        ...
        
        $this->nav->title = static::titleIndex();

        ...
    }

    public function actionView()
    {
        ...
        
        $this->nav->title = static::titleView();        
        $this->nav->crumbs = static::crumbsToIndex();

        ...
    }

}

В этом примере класс OrderController отвечает за заказы. Действие order/index будет имеет заголовок "Заказы". Логично, что слово "Заказы" также должно быть пунктом главного меню приложения, а также частью хлебных крошек для других действий. Как видите, это слово можно получить из любого места приложения, вызвав метод OrderController::titleIndex().

Аналогично с хлебными крошками. Например, если появляется класс ItemController, отвечающий за товары в заказе, то действие item/create может иметь хлебные крошки "Главная / Заказы / Заказ № 1 / Добавить товар". Для формирования таких хлебных крошек в классе ItemController достаточно будет вызвать $this->nav->crumbs = OrderController::crumbsToView($item->order).

Подобный подход реализован в шаблонах Gii, входящих в состав YIMP.

Дополнительно
Виджеты

Свободное место в футере и боковых панелях может быть использовано для виджетов. Если вам нужно вывести виджет только для одного действия, вы можете в представлении для этого действия определить блок:

<?php $this->beginBlock(Yimp::SIDEBAR_RIGHT); ?>
    <div class="border rounded p-3 mt-3">
        <div class="h5">Caption</div>
        Your widget HTML
    </div>
<?php $this->endBlock(); ?>

Для использования блоков в YIMP определены константы Yimp::SIDEBAR_LEFT, Yimp::SIDEBAR_RIGHT, Yimp::FOOTER.

Обратите внимание, что боковые панели с виджетами отображаются только на больших экранах (xl). Для меньших экранов рекомендуется переопределить виджеты подобно тому, как это сделано для элементов управления формой.

Иконки

Поскольку Bootstrap 4 не поддерживает иконки, в YIMP используются иконки от FontAwesome. Они подключаются в момент регистрации ресурсов YIMP, поэтому вы можете использовать их в своем приложении согласно документации к FontAwesome.

Меню

Для настройки левого, правого и верхнего меню используются свойства навигатора menuLeft, menuRight и menuTop. В этих свойствах необходимо указать настройки для свойства yiisoft/bootstrap4/Nav::items, например так:

    public function actionIndex()
    {
        ... 

        $this->nav->menuRight = [
            ['label' => 'Options'],
            ['label' => static::titleCreate(), 'url' => ['create']],
        ];

        ...
    }

Помимо известных настроек, могут быть указаны также следующие настройки:

  • active: В оригинальном виджете он имеет тип bool. В YIMP можно также использовать строку, соответствующую маске маршрута. Например, если для главного меню указать 'active' => 'order/*', пункт будет активен для любого действия из OrderController. Подробности см. MenuAdapter, RouteHelper.
  • visibleMode: YIMP рендерит каждое меню дважды - для десктопов и для мобильных устройств. Если вы хотите вывести элемент только для одного типа устройств, укажите здесь Yimp::DESKTOP или YIMP::MOBILE. Обратите внимание, что эта настройка никак не связана с CSS.
Стилизация

YIMP написан с расчетом на максимальное использование возможностей Bootstrap 4. Все, что можно было сделать классами Bootstrap 4, сделано именно так. Тем не менее, для части элементов пришлось определять собственные стили, которые используют переменные Bootstrap 4 в основном для определения цветов. Стили Yimp хранятся в файле vendor\dmitrybtn\yii2-yimp\assets\css\yimp.scss.

Если вы решите использовать собственную таблицу стилей, то нужно отключить стили Bootstrap и стили Yimp, указав в настройках приложения:

    'assetManager' => [
        'bundles' => [
            'yii\bootstrap4\BootstrapAsset' => [
                'css' => [],
            ],
            'dmitrybtn\yimp\Asset' => [
                'css' => [],
            ]
        ]
    ]
]]>
0
[news] Yii 2.0.26 Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/news/247/yii-2-0-26 https://www.yiiframework.com/news/247/yii-2-0-26 samdark samdark

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

Version 2.0.26 is a minor release of Yii 2.0. This release includes bug fixes accumulated since last release.

Thanks to all Yii community members who contribute to the framework, translators who keep documentation translations up to date and community members who answer questions at forums.

There are many active Yii communities so if you need help or want to share your experience, feel free to join them.

A complete list of changes can be found in the CHANGELOG.

]]>
0
[extension] slavkovrn/yii2-jsoneditor Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/slavkovrn/yii2-jsoneditor https://www.yiiframework.com/extension/slavkovrn/yii2-jsoneditor Viacheslav Kolesnikov Viacheslav Kolesnikov

JsonEditor widget for Yii2 Framework uses Json Editor plugin for jQuery

  1. Installation
  2. Usage

JsonEditor widget demo page

The extension uses Json Editor plugin by Author Jadesoul http://jadesoul.org for jQuery and makes user interface for changing json values.

JsonEditor widget

Installation

The preferred way to install this extension is through composer.

Either run:

composer require slavkovrn/yii2-jsoneditor

or add

"slavkovrn/yii2-jsoneditor": "*"

to the require section of your composer.json file.

Usage

Set link to extension in your view:

<?php
use slavkovrn\jsoneditor\JsonEditorWidget;
use yii\widgets\ActiveForm;
use yii\helpers\Html;
?>
    <?php $ form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'username')->widget(JsonEditorWidget::class,[
        'rootNodeName' => 'root1',
    ]) ?>

    <?= $form->field($model, 'email')->widget(JsonEditorWidget::class,[
        'rootNodeName' => 'root2',
    ]) ?>

    <div class="form-group">
        <?= Html::submitButton('Save', ['class' => 'btn btn-success']) ?>
    </div>

    <?php ActiveForm::end(); ?>​

write comments to admin

]]>
0
[extension] razonyang/yii2-rate-limiter Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/razonyang/yii2-rate-limiter https://www.yiiframework.com/extension/razonyang/yii2-rate-limiter razonyang razonyang

Yii2 Rate Limiter

  1. Backends
  2. Installation
  3. Usage

Build Status Scrutinizer Code Quality Code Coverage Latest Stable Version Total Downloads LICENSE

Backends

Installation

composer require razonyang/yii2-rate-limiter

Usage

Let's take 5000 requests every hours as example:

return [
    public function behaviors()
    {
        return [
            // redis via redis extension
            'rateLimiter' => [
                'class' => \RazonYang\Yii2\RateLimiter\RedisRateLimiter::class,
                'password' => '',
                'hostname' => 'localhost',
                'port' => 6379,
                'capacity' => 5000,
                'rate' => 0.72,
                'limitPeriod' => 3600,
                'prefix' => 'rate_limiter:',
                'ttl' => 3600,
                // 'nameCallback' => $callback,
            ],
            // redis via yii2-redis
            'rateLimiter' => [
                'class' => \RazonYang\Yii2\RateLimiter\Redis\RateLimiter::class,
                'redis' => 'redis', // redis component name or definition
                'capacity' => 5000,
                'rate' => 0.72,
                'limitPeriod' => 3600,
                'prefix' => 'rate_limiter:',
                'ttl' => 3600,
                // 'nameCallback' => $callback,
            ],

            // memcached
            'rateLimiter' => [
                'class' => \RazonYang\Yii2\RateLimiter\MemcachedRateLimiter::class,
                'hostname' => 'localhost',
                'port' => 11211,
                'capacity' => 5000,
                'rate' => 0.72,
                'limitPeriod' => 3600,
                'prefix' => 'rate_limiter:',
                'ttl' => 3600,
                // 'nameCallback' => $callback,
            ],
        ];
    }
];

RateLimiter takes uid:route(authorized) or ip:route(guest) as bucket name, you can also change this behavior via nameCallback:

$nameCallback = function (
    \yii\web\User $user,
    \yii\web\Request $request,
    \yii\base\Action $action
): string {
    return 'bucket name';
}
]]>
0
[extension] razonyang/yii2-app-template Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/razonyang/yii2-app-template https://www.yiiframework.com/extension/razonyang/yii2-app-template razonyang razonyang
  1. Yii2 App Template
  2. DEMO
  3. DOCUMENTATION
  4. DIRECTORY STRUCTURE
  5. Credit

Yii2 App Template

Build Status Scrutinizer Code Quality Code Coverage Latest Stable Version Total Downloads LICENSE

Yii2 App Project Template is a skeleton Yii 2 application best for developing complex web applications with multiple tiers.

There is a Yii2 Vue Admin for building a back end application.

DEMO

DOCUMENTATION

DIRECTORY STRUCTURE

app
    Console/             
        Controller/              contains console controller classes
        Model/                   contains console model classes
        Job/                     contains console job classes
    Exception/                   contains exception classes
    Form/                        contains form classes
    Http/
       Api/
           Backend/              contains back end API classes
           Frontend/             contains front end API classes
       Asset/                    contains web assets such as JavaScript and CSS
       Controller/               contains web controller classes
       Filter/                   contains web filters
       Form/                     contains web form classes
       Model/                    contains web model classes
       Module/                   contains web modules
       Widget/                   contains web widgets
    Job/                         contains web job classes
    Model/                       contains model classes
    Rbac/
        Rule/
    Validator/                   contains validators
bin/                             contains scripts
conf/                            contains conf files, such as crond job, systemd service unit etc
config/                          contains all of app configurations
public/                          contains the entry script and web resources
resources
    environments/                contains environment-based overrides
    mail/                        contains view files for e-mails
    messages/                    contains I18N messages
    migrations/                  contains database migrations
    views/                       contains view files for the Web application
tests/                           contains tests    
vendor/                          contains dependent 3rd-party packages

Credit

It is a fork of Yii2 Advanced Template

]]>
0
[extension] razonyang/yii2-uploader Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/razonyang/yii2-uploader https://www.yiiframework.com/extension/razonyang/yii2-uploader razonyang razonyang

Yii2 Uploader

  1. Installation
  2. Usage

Build Status Scrutinizer Code Quality Code Coverage Latest Stable Version Total Downloads LICENSE

Supports multiple filesystems:

Installation

composer require razonyang/yii2-uploader

Usage

Configuration:

return [
    'components' => [
        'filesystem' => [
            'class' => \creocoder\flysystem\LocalFilesystem::class,
            'path' => '@webroot/resources',
        ],
        'uploader' => [
            'class' => \RazonYang\Yii2\Uploader\Uploader::class,
            'host' => 'http://localhost/resources', // the hostname relative to your uploaded files
            'filesystem' => 'filesystem',
        ],
    ],
];

And then defines a form, UploadForm

class UploadForm extends \yii\base\Model
{
    use \RazonYang\Yii2\Uploader\UploadModelTrait;

    public function handle()
    {
        if (!$this->validate()) {
            // handles error
            throw new \Exception('invalid file');
        }

        $url = $this->upload();
        return [
            'url' => $url,
            // ... other information
        ];
    }
}

class UploadController extends \yii\web\Controller
{
    public function actionUpload()
    {
        $form = new UploadForm([
            'file' => \yii\web\UploadedFile::getInstanceByName('file')
        ]);
        return $form->handle();
    }
}
]]>
0
[news] ApiDoc extension version 2.1.2 released Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/news/246/apidoc-extension-version-2-1-2-released https://www.yiiframework.com/news/246/apidoc-extension-version-2-1-2-released samdark samdark

We are very pleased to announce the release of the ApiDoc extension version 2.1.2.

This release upgrades highlight.js dependency to 9.13.1 and fixes multiple TOC rendering in ApiMarkdown.

See the CHANGELOG for a full list of changes.

]]>
0
[extension] owk/yii2-circular-navigation Tue, 20 Aug 2019 23:11:05 +0000 https://www.yiiframework.com/extension/owk/yii2-circular-navigation https://www.yiiframework.com/extension/owk/yii2-circular-navigation owk owk

Yii2 Circular navigation

  1. Installation
  2. Usage

Created by Codrops

http://www.codrops.com

>Integrate or build upon it for free in your personal or commercial projects. Don't republish, redistribute or sell "as-is".

Read more here: licensing

edited by owk

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist owk/yii2-circular-navigation

or add

"owk/yii2-circular-navigation": "^1.0.0"

to the require section of your composer.json file.

Usage

Once the extension is installed, simply use it in your view by : `php <?php echo owk\circularnavigation\CircularNavigation::widget([

            'cnoptions'=>[
                'menu' =>[
                    'background_color' => '#0088cd',
                    'background_color_hover' => 'rgb(12, 135, 212)',
                    // 'openLabel' => 'Menú',
                    // 'closeLabel' => 'Cerrar',
                    // 'color' => 'white'
                ],
                'item' => [
                    'background_color' => '-webkit-linear-gradient(90deg, #666666 0%,#319ed8 50%,#666666 100%)',
                    // 'background_color' => '#000',
                    // 'background_color_hover' => '#0088cd'
                ]
            ],
            'items' => [
                
                [
                    'url' =>'#',
                    'icon' =>'glyphicon-list-alt'
                ],
                [
                    'url' =>'/',
                    'icon' =>'glyphicon-home'
                ],
                [
                    'url' =>'#editar',
                    'icon' =>'glyphicon-pencil'
                ],
                // [
                //     'url' =>'#enviar',
                //     'icon' =>'glyphicon-send'
                // ],
                [
                    'url' =>'#table',
                    'icon' =>'glyphicon-duplicate'
                ]
                ,
                [
                    'url' =>'#aceptar',
                    'icon' =>'glyphicon-phone'
                ]
            ]
            ]);?>

]]>
0
[news] Debug extension 2.1.8 released Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/news/245/debug-extension-2-1-8-released https://www.yiiframework.com/news/245/debug-extension-2-1-8-released samdark samdark

Debug extension version 2.1.8 was released.

This version fixes two bugs:

  • Infinite redirect when URL normalizer is turned on
  • Broken user switching from the toolbar

See the CHANGELOG for details.

]]>
0
[wiki] Move sources to src Tue, 27 Aug 2019 21:43:50 +0000 https://www.yiiframework.com/wiki/2550/move-sources-to-src https://www.yiiframework.com/wiki/2550/move-sources-to-src samdark samdark

Yii 3 and many Yii 2 package sources are contained within src directory which is convenient since you have less directories to check.

/config
/runtime
/src
  /assets
  /commands
  /controllers
  /mail
  /models
  /views
  /widgets
/tests
/vendor
/web
yii

Let's start with the basic applicaiton template.

  1. Create src directory.
  2. Move source directories there.
  3. Adjust config/web.php:
$config = [
    // ...
    'basePath' => dirname(__DIR__) . '/src',
    'runtimePath' => dirname(__DIR__) . '/runtime',
    'vendorPath' => dirname(__DIR__) . '/vendor',    
    // ...
];

And config/console.php:

$config = [
    // ...
    'basePath' => dirname(__DIR__) . '/src',
    'runtimePath' => dirname(__DIR__) . '/runtime',
    'vendorPath' => dirname(__DIR__) . '/vendor',
    // ...
];

That's it now you have both console and web application source code in src.

]]>
0
[news] Yii 2.0.25 Tue, 13 Aug 2019 20:09:34 +0000 https://www.yiiframework.com/news/244/yii-2-0-25 https://www.yiiframework.com/news/244/yii-2-0-25 samdark samdark

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

Version 2.0.25 is a minor release of Yii 2.0. This release includes bug fixes accumulated since last release.

Thanks to all Yii community members who contribute to the framework, translators who keep documentation translations up to date and community members who answer questions at forums.

There are many active Yii communities so if you need help or want to share your experience, feel free to join them.

A complete list of changes can be found in the CHANGELOG.

]]>
0
[news] Gii extension 2.1.1 released Tue, 13 Aug 2019 14:37:18 +0000 https://www.yiiframework.com/news/243/gii-extension-2-1-1-released https://www.yiiframework.com/news/243/gii-extension-2-1-1-released samdark samdark

We are very pleased to announce the release of Gii extension version 2.1.1 fixing a bug not highlighting part of the diff preview.

See the CHANGELOG for details.

]]>
0
[news] Bootstrap 4 extension version 2.0.7 released Tue, 13 Aug 2019 11:53:10 +0000 https://www.yiiframework.com/news/242/bootstrap-4-extension-version-2-0-7-released https://www.yiiframework.com/news/242/bootstrap-4-extension-version-2-0-7-released samdark samdark

Bootstrap 4 extension version 2.0.7 was released. This version fixes a bug in displaying error message for checkbox and radio lists and allowing to override all CSS classes via widget factory.

Thanks to @simialbi for taking care of the extension!

See CHANGELOG for details.

]]>
0
[extension] diecoding/yii2-core Mon, 12 Aug 2019 16:01:55 +0000 https://www.yiiframework.com/extension/diecoding/yii2-core https://www.yiiframework.com/extension/diecoding/yii2-core die-coding die-coding

Yii2 Core

  1. Cara Memasang
  2. List Class

Tidak ada dokumentasi, karena hanya untuk tambahan internal Die Coding saja ^_^

Latest Version Software License Quality Score Total Downloads

Cara Memasang

  • Melalui console
composer require --prefer-dist diecoding/yii2-core "dev-master"
  • Melalui composer.json
  1. Tambahkan pada baris require
"diecoding/yii2-core": "dev-master"
  1. Kemudian jalankan
composer update

List Class

\diecoding\behaviors\TouchDbBehavior();

\diecoding\behaviors\TouchDbBehavior();


\diecoding\helpers\Date();
]]>
0
[extension] razonyang/yii2-jsend Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/razonyang/yii2-jsend https://www.yiiframework.com/extension/razonyang/yii2-jsend razonyang razonyang

JSend port for Yii2

  1. Installation
  2. Usage
  3. Error Handler

Build Status Scrutinizer Code Quality Code Coverage Latest Stable Version Total Downloads LICENSE

The package is a Yii2's implementation of JSend specification.

Installation

composer require razonyang/yii2-jsend

Usage

Update resposne formater and error handler:

return [
    'components' => [
        'response' => [
            'formatters' => [
                \yii\web\Response::JSON => [
                    'class' => \RazonYang\Yii2\JSend\Formatter::class,
                ],
            ],
        ],
        'errorHandler' => [
            'class' => \RazonYang\Yii2\JSend\ErrorHandler::class,
        ],
    ],
];

Change you rest controller serializer:

public $serializer = \RazonYang\Yii2\JSend\Serializer::class;

Error Handler

ErrorHandler converts exception to error payload:

{
    "status": "error",
    "code": "exception code",
    "message": "exception message"
}

It can also returns the optional data field by throwing a JSend's Exception:

throws new RazonYang\Jsend\Exception($message, $code, $data, $previous);

// you can also define your own exception:
class MyException extends RazonYang\Jsend\Exception
{
}

throws new MyException();
{
    "status": "error",
    "code": "exception code",
    "message": "exception message",
    "data": "exception data"
}
]]>
0
[extension] instafeed Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/instafeed https://www.yiiframework.com/extension/instafeed IlliaBasharov IlliaBasharov
  1. Requirements
  2. Installation
  3. Usage
  4. Resources

...overview of the extension...

Requirements

...requirements of using this extension (e.g. Yii 2.0 or above)...

Installation

...how to install the extension (e.g. composer install extensionname)...

Usage

...how to use this extension...

...can use code blocks like the following...

$model=new User;
$model->save();

Resources

DELETE THIS SECTION IF YOU DO NOT HAVE IT

...external resources for this extension...

  • [Project page](URL to your project page)
  • [Try out a demo](URL to your project demo page)
]]>
0
[news] Yii 2.0.24 Tue, 30 Jul 2019 15:57:22 +0000 https://www.yiiframework.com/news/241/yii-2-0-24 https://www.yiiframework.com/news/241/yii-2-0-24 samdark samdark

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

Version 2.0.24 is a minor release of Yii 2.0. In this release 8 bugs were fixed.

It includes further work on MSSQL, migration fixes, subdomain support for User::loginRequired() and a fix for logger replacement.

Thanks to all Yii community members who contribute to the framework, translators who keep documentation translations up to date and community members who answer questions at forums.

There are many active Yii communities so if you need help or want to share your experience, feel free to join them.

A complete list of changes can be found in the CHANGELOG.

]]>
0
[news] Debug extension 2.1.7 released Tue, 30 Jul 2019 12:50:23 +0000 https://www.yiiframework.com/news/240/debug-extension-2-1-7-released https://www.yiiframework.com/news/240/debug-extension-2-1-7-released samdark samdark

Debug extension version 2.1.7 was released.

This version fixes regression in previous release regarding edge cases of closure serialization, fixes insufficient ouput escaping that may lead to XSS and adds "since previous" and sequential number to "logs" panel detail view:

aop7x-ywototms6dffcoa0_5jmo.png

See the CHANGELOG for details.

]]>
0
[extension] wxxiong6/yii-seaslog Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/wxxiong6/yii-seaslog https://www.yiiframework.com/extension/wxxiong6/yii-seaslog wxxiong6 wxxiong6

yii2-seasLog extension

  1. Requirements
  2. Installation
  3. Usage
  4. Changelog

使用SeasLog高效日志扩展替换Yii2框架的日志模块,使其提高写日志效率。只需配置就可以实现。

SeasLog扩展https://github.com/SeasX/SeasLog/

Requirements

  • Yii2
  • PHP >=5.4
  • ext-seaslog installed

Installation

composer require wxxiong6/yii-seaslog:"1.0.0"

Usage

main.php

    'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [
                'default' => [
                    'class' => 'wxxiong6\yii\seaslog\Yii2SeasLog',
                    'levels' => ['trace', 'info', 'error', 'warning'],
                    'logFile' => 'backend/runtime/',
                    'logVars' => [],
                ],
            ],
        ],

为了跟yii2日志格式一致,修改php.ini seaslog日志格式

seaslog.default_template = %T %M

Changelog

Release 1.0 - Changelog
  • Official stable release
]]>
0
[extension] practically/yii2-chartjs Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/practically/yii2-chartjs https://www.yiiframework.com/extension/practically/yii2-chartjs AdeAttwood AdeAttwood

Yii2 Chart JS

  1. Installation
  2. Usage
  3. Contributing
  4. Credits

Wrapper for chart js in Yii2. Easily turn Yii2 querys into beautiful charts.

Installation

The preferred way is with composer.

composer require practically/yii2-chartjs

Note: This package does not handle the installation of chart js library. For that you can visit the chart js website

You can also install with the asset packagist

composer require bower-asset/chart-js

Usage

Basic usage
use practically\chartjs\Chart;

echo Chart::widget([
    'type' => Chart::TYPE_BAR,
    'datasets' => [
        [
            'data' => [
                'Label 1' => 10,
                'Label 2' => 20,
                'Label 3' => 30
            ]
        ]
    ]
]);
Using a db query to define the data
echo Chart::widget([
    'type' => Chart::TYPE_BAR,
    'datasets' => [
        [
            'query' => Model::find()
                ->select('type')
                ->addSelect('count(*) as data')
                ->groupBy('type')
                ->createCommand(),
            'labelAttribute' => 'type'
        ]
    ]
]);
Adding dom options
echo Chart::widget([
    ...

    'options' => [
        'class' => 'chart',
        'data-attribute' => 'my-value'
    ],

    ...
]);
Adding client options

In the client options array you can define any property to be json encoded and passed to the chart js constructor.

echo Chart::widget([
    ...

    'clientOptions' => [
        'title' => [
            'display' => true,
            'text' => 'My New Title',
        ],
        'legend' => ['display' => false],
    ]

    ...
]);
Formatting the y axes
echo Chart::widget([
    ...

     'clientOptions' => [
        'scales' => [
            'yAxes' => [
                [
                    'ticks' => [
                        'callback' => new JsExpression('function(value, index, values) {
                             return \'£\'+value;
                        }')
                    ]
                ]
            ]
        ],
        'tooltips' => [
            'callbacks' => [
                'label' => new JsExpression('function(tooltipItem, chart) {
                    var datasetLabel = chart.datasets[tooltipItem.datasetIndex].label || \'\';
                    return datasetLabel + \' £\'+tooltipItem.yLabel;
                }')
            ]
        ]
    ]

    ...
]);
Adding chart js events
Chart::widget([
    'type' => Chart::TYPE_DOUGHNUT,
    'jsVar' => 'DoughnutChart',
    'jsEvents' => [
        'onclick' => new JsExpression('function(e) {
            var el = DoughnutChart.getElementAtEvent(e);
            window.location.href = "/search/ + el[0]._model.label;
        }')
    ]
]);

Contributing

Getting set up

Clone the repo and run composer install. Then start hacking!

Testing

All new features of bug fixes must be tested. Testing is with phpunit and can be run with the following command

composer run-script test
Coding Standards

This library uses psr2 coding standards and squizlabs/php_codesniffer for linting. There is a composer script for this:

composer run-script lint
Pull Requests

Before you create a pull request with you changes, the pre-commit script must pass. That can be run as follows:

composer run-script pre-commit

Credits

This package is created and maintained by Practically.io

]]>
0
[news] Debug extension 2.1.6 released Tue, 23 Jul 2019 20:30:20 +0000 https://www.yiiframework.com/news/239/debug-extension-2-1-6-released https://www.yiiframework.com/news/239/debug-extension-2-1-6-released samdark samdark

Debug extension version 2.1.6 was released containing five enhancements:

  • Total request processing time and peak memory consumption were added on index page for each request
  • Improved error when no debug data present
  • Browser compatibility was improved so toolbar now works with IE and older browsers
  • Closures are now serialized with the help of opis/closure eliminating related issues
  • Module got tracePathMappings option that allows you to fine tune stacktrace links to work for Docker image with file system mapped to host machine

See the CHANGELOG for details.

]]>
0
[news] Bootstrap 4 extension version 2.0.6 released Tue, 23 Jul 2019 16:32:56 +0000 https://www.yiiframework.com/news/238/bootstrap-4-extension-version-2-0-6-released https://www.yiiframework.com/news/238/bootstrap-4-extension-version-2-0-6-released samdark samdark

Bootstrap 4 extension version 2.0.6 was released. In this version there are two changes.

First, documentation on how to migrate from Bootstrap 3 was added.

Second, simplified syntax for progress bars that was present in Bootstrap 3 was brought back:

echo Progress::widget([
     'percent' => 65,
     'barOptions' => ['class' => 'progress-bar-danger']
]);

Thanks to @simialbi for both changes.

See CHANGELOG for details.

]]>
0
[extension] yii-ui/yii2-flag-icon-css-widget Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/yii-ui/yii2-flag-icon-css-widget https://www.yiiframework.com/extension/yii-ui/yii2-flag-icon-css-widget cmoeke cmoeke

Yii UI Yii UI - Yii2 Flag icon css - Widget

  1. Installation
  2. Usage
  3. Documentation
  4. License

Latest Stable Version Total Downloads Yii2 License

This is an Yii framework 2.0 widget of the Lipis flag-icon-css package.

If you are looking for the asset bundle, please install yii-ui/yii2-flag-icon-css-asset-bundle.

Installation

The preferred way to install this extension is through composer.

Either run php composer.phar require yii-ui/yii2-flag-icon-css-widget or add "yii-ui/yii2-flag-icon-css-widget": "^1.0" to the require section of your composer.json file.

Usage

use yiiui\yii2flagiconcss\widget\FlagIcon;

echo FlagIcon::widget([
    'countryCode' => 'de',
    'options' => [
        'class' => 'example-flag'
    ],
    'squared' => true,
]);

See https://www.yii-ui.com/packages/yii2-flag-icon-css-widget for more infos. For plugin configuration see Lipis flag-icon-css Documentation.

Documentation

Documentation can be found at https://www.yii-ui.com/packages/yii2-flag-icon-css-widget/docs.

License

yii2-flag-icon-css-widget is released under the MIT License. See the LICENSE for details.

]]>
0
[extension] yii-ui/yii2-flag-icon-css-asset-bundle Tue, 06 Aug 2019 10:00:34 +0000 https://www.yiiframework.com/extension/yii-ui/yii2-flag-icon-css-asset-bundle https://www.yiiframework.com/extension/yii-ui/yii2-flag-icon-css-asset-bundle cmoeke cmoeke ]]> 0 [extension] execut/yii2-import Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/extension/execut/yii2-import https://www.yiiframework.com/extension/execut/yii2-import eXeCUT eXeCUT

Latest Version Build Status Coverage Status Scrutinizer Code Quality SensioLabsInsight Packagist Downloads

yii2-import

Fast and flexible Yii2 module for importing and synchronizing anything into the database through activeRecord

Installation

The preferred way to install this extension is through composer.

Install

Either run

$ php composer.phar require execut/yii2-import "dev-master"

or add

"execut/yii2-import": "dev-master"

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

Configuration

Add module bootstrap and application language in target web application config: `php

...
'language' => 'ru',
'bootstrap' => [
...
    'import' => [
        'class' => \execut\import\bootstrap\Backend::class,
    ]
...
],

Add module bootstrap in console application config:
```php
    'bootstrap' => [
    ...
        'import' => [
            'class' => \execut\import\bootstrap\Console::class,
        ]
    ...
    ],

For activate i18n translation set you application language in config: `php


Apply migrations via yii command:

./yii migrate/up --migrationPath=vendor/kartik-v/yii2-dynagrid/src/migrations `

After configuration, the module should open by paths: import/files import/settings

Module navigation

You may output navigation of module inside your layout via execut/yii2-navigation: `php

echo Nav::widget([
    ...
    'items' => \yii\helpers\ArrayHelper::merge($menuItems, \yii::$app->navigation->getMenuItems()),
    ...
]);
NavBar::end();

// Before standard breadcrumbs render breadcrumbs and header widget:
echo \execut\navigation\widgets\Breadcrumbs::widget();
echo \execut\navigation\widgets\Header::widget();
For more information about execut/yii2-navigation module, please read it [documentation](https://github.com/execut/yii2-navigation)

Further instructions will be in Russian, because there is no time to translate, your help is welcome.

### Описание разделов
#### Файлы

По адресу import/files происходит управление файлами, которые импортируются. Здесь можно вручную загружать новые
и управлять загрузками. Каждому файлу можно выставить статусы и консольная команда для импорта подхватит его:
* New - загрузить файл
* Reload - перезагрузиь файл
* Delete - удалить файл
* Loaded - файл загружен
* Stop - остановить загрузку
* Error - ошибка загрузки файла

Остальные статусы используются консольной командой для отображения процесса импорта и если их выставить вручную,
поведение импорта непредсказуемо:
* Loading - файл в процессе импорта
* Stopped - импорт файла остановлен
* Deleting - файл в процессе удаления

#### Настройки

По адресу import/settings можно управлять настройками, через которые происходит захват файлов их внешних источников,
разбор файлов на данные и их запись в базу данных.

Чтобы начать производить настройки импорта, модулю необходимо указнать про ваше окружение базы данных через реализацию
плагина execut\import\Plugin. Подробнее о том как реализовать этот плагин, смотрите раздел
[создание плагинов](#создание-плагинов)

#### Консоль

В консоли есть 3 команды:
##### import
Команда ./yii import запускает процесс импорта и удаления файлов. Этот процесс пошагово выглядит так:
1. Отбирается самый старый по дате создания файл со статусом New и Reload
2. Удаляется старый файл с такой-же настройкой как и новый
3. Происходит его парсинг и запись в БД
4. Шаг 1 повторяется

Эта команда поддерживает её параллельный запуск для большей скорости импорта.
У команды есть единственный необязательный аргумент: идентификатор файла, который необходимо импортировать. Если его
передать, то указанный файл начнёт импортироваться через шаги 1-3. После выполнения шага 3 процесс выполнения команды
обрывается

##### import/check-source
./yii import/check-source выполняет процесс захвата файлов из внешних источников через настройки и их запись в базу для
последующего запуска.
Аргументы команды:
* type - тип источника. Может быть email, ftp или site.
* id - идентификатор настройки. Если указать его, то произойдёт захват только указанной настройки.

Команда поддерживает параллельный запуск.

##### import/release-trigger
./yii import/release-trigger очищает все mutex-триггеры. Применяется для случаев, если произошёл сбой при выполнении
команд для разблокировки их дальнейшего выполнения.

##### Автоматический захват файлов
Для системы Linux есть два способа настройки автоматического захвата файлов. Через cron или с помощью службы systemd.
###### Systemd
Через службу systemd желательней, поскольку ею пользоваться удобнее и не нужно заботиться об отказоустойчивости демона.
Служба сама будет перезапускаться в случае его отказа. Для настройки службы нужно создать unit нового сервиса. В случае
ubuntu для этого нужно создать файл yii2-import.service в папке /etc/systemd/system/ со следующим содержимым:

[Unit] Description=eXeCUT Yii2 import service

[Service] Type=simple User={Пользователь, из под которого происходит запуск приложения} ExecStart={Путь до приложения}/yii import/check-source-daemon email Restart=always

[Install] WantedBy=multi-user.target `

После этого можно запустить службу командой service yii2-import start и следить за ней через лог /var/log/syslog

Cron

Чтобы запускать по крону необходимо добавить новый файл в папке /etc/cron.d/ или новые строчки в файл /etc/crontab со следующим содержимым: */5 * * * * {Пользователь} {Путь до приложения}/yii import/check-source 0 8 * * * {Пользователь} {Путь до приложения}/yii import/check-source ftp; 0 8 * * * {Пользователь} {Путь до приложения}/yii import/check-source site; Этот пример запускает раз в 5 минут захват почты и в 8 утра захват с фтп и сайтов.

Создание плагинов
Создание простых записей

Для изучения принципа создания плагина, рассмотрим простой пример. У нас есть товар. У товара есть название и цена. Нам нужно импортировать этот товар в базу данных каталога. Применим миграции примера: `ssh ./yii migrate/up --migrationPath=vendor/execut/yii2-import/example/migrations `

Подключим плагин простого плагина через конфигурационные файлы двух приложений консольного и web, в тех строках, что мы задавали раннее для запуска модуля: `php

            'import' => [

//'class' => \execut\import\bootstrap\Console::class,

                'depends' => [
                    'modules' => [
                        'import' => [
                            'plugins' => [
                                'simple' => [
                                    'class' => \execut\import\example\Plugin::class,
                                ],
                            ],
                        ],
                    ],
                ],
            ],

После этого в админке настроек импорта появляется возможность задавать настройки для ипорта товаров с
двумя полями: названием и ценой.
Перейдём по адресу import/settings и создадим в этой админке настройку со следующими полями:

1. Название: Простой товар
1. Пропустить строк: 1
1. Кодировка файла: UTF-8
1. Источник захвата файла: Вручню
1. Листы
   1. Название: Первый лист
       1. Тип: Product
           1. Тип: Product name, Колонка: 1
           1. Тип: Product price, Колонка: 2

![Sheet example](docs/sheet.jpg)

В результате мы настроили возможность загружать файл, расположенный внутри папки компонента: example/data/products.gnumeric
Попробуем его загрузить через админку файлов импорта import/files, выбрав следующие значения полей:
1. Файл: выбираем файл example/data/products.gnumeric
1. Настройки: выбираем раннее созданную настройку "Простой товар"
1. Источник захвата файла: Вручную

И пробуем этот файл загрузить в базу через консольную команду:
```bash
> ./yii import
Start check failed files
End check failed files
Start parse file #1 products.gnumeric
start extract example_product_id
start construct where example_product_id
end construct where example_product_id after 0.0058150291442871 seconds
start find example_product_id
end find example_product_id after 0.014003992080688 seconds
start keys collect example_product_id
end keys collect example_product_id after 4.0531158447266E-6 seconds
start models collect example_product_id
end models collect example_product_id after 0.24526405334473 seconds
end extract example_product_id after 0.26518106460571 seconds
Row #0: Saving example_products # a:2:{s:4:"name";s:1:"1";s:5:"price";s:9:"Product 1";} because they is created
Row #1: Saving example_products # a:2:{s:4:"name";s:1:"2";s:5:"price";s:9:"Product 2";} because they is created
Row #2: Saving example_products # a:2:{s:4:"name";s:1:"3";s:5:"price";s:9:"Product 3";} because they is created
...

В результате импорта в таблице example_products должны появиться 2500 товаров

Создание записей через связи

Расширим пример выше, но, уже импортируя товар через артикулы. Для этого подключим другой плагин указанным выше образом: execut\import\example\withRelations\Plugin Этот плагин позволит загружать и синхронизировать товары по связке их артикул\производитель. Необходимо скорректировать созданную раннее настройку, указав 3 и 5 столбец как Article и Brand соответственно. После этого указываем статус файла "Перезагрузить" и загружаем его вновь: `bash > ./yii import `

После этого должны появиться 3 производителя, 2499 их артикулов и 2499 товаров с ними. Если попробовать вновь загрузить файл, то ничего не должно измениться в БД, поскольку изменений в файле не было.

Усложненный поиск записей

Есть возможность усложнить поиск записей, если, например, в файлах один и тот-же производитель может называться по разному. Для этого модели производителя необходимо наследовать интерфейс execut\import\ModelInterface и вычислить в нём все возможные варианты названия активного производителя, а в объекте запроса ActiveQuery для этой модели унаследовать execut\import\Query и в нём задать новый способ поиска.

]]>
0
[news] Yii 2.0.23 Tue, 16 Jul 2019 20:37:03 +0000 https://www.yiiframework.com/news/237/yii-2-0-23 https://www.yiiframework.com/news/237/yii-2-0-23 samdark samdark

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

Version 2.0.23 is a minor release of Yii 2.0. In this release 5 bugs were fixed with the main focus on MSSQL database support. All fixes were made by Alexander Kartavenko. Thank you!

Thanks to all Yii community members who contribute to the framework, translators who keep documentation translations up to date and community members who answer questions at forums.

There are many active Yii communities so if you need help or want to share your experience, feel free to join them.

A complete list of changes can be found in the CHANGELOG.

]]>
0
[news] Yii 2.0.22 Tue, 02 Jul 2019 20:55:42 +0000 https://www.yiiframework.com/news/236/yii-2-0-22 https://www.yiiframework.com/news/236/yii-2-0-22 samdark samdark

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

Version 2.0.22 is a minor release of Yii 2.0. In this release community members fixed 6 bugs. Additionally, two very minor enhancements were made.

  • \yii\validators\DateValidator got $strictDateFormat property that enables stricter validation mode.
  • Debug log message for \yii\base\Action now includes controller name.

Thanks to all Yii community members who contribute to the framework, translators who keep documentation translations up to date and community members who answer questions at forums.

Special thanks to Alexander Kartavenko who contributed majority of release fixes.

There are many active Yii communities so if you need help or want to share your experience, feel free to join them.

A complete list of changes can be found in the CHANGELOG.

]]>
0
[news] Sphinx extension 2.0.12 released Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/news/235/sphinx-extension-2-0-12-released https://www.yiiframework.com/news/235/sphinx-extension-2-0-12-released samdark samdark

We are very pleased to announce the release of Sphinx extension version 2.0.12. This release fix compatibiltiy with Yii 2.0.21.

See the CHANGELOG for details.

]]>
0
[news] Auth Client extension 2.2.4 released Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/news/234/auth-client-extension-2-2-4-released https://www.yiiframework.com/news/234/auth-client-extension-2-2-4-released samdark samdark

We are very pleased to announce the release of Auth Client extension version 2.2.4.

In this release there is one important fix about return URLs of OAuth services. Now, by default, only parameters specified via parametersToKeepInReturnUrl are kept while extra ones are removed. That should fix Google client that changed behavior recently.

See the CHANGELOG for details.

]]>
0
[news] Bootstrap 4 extension version 2.0.5 released Tue, 02 Jul 2019 10:28:00 +0000 https://www.yiiframework.com/news/233/bootstrap-4-extension-version-2-0-5-released https://www.yiiframework.com/news/233/bootstrap-4-extension-version-2-0-5-released samdark samdark

Bootstrap 4 extension version 2.0.5 was released. In this release ActiveField got two options, radioTemplate and radioHorizontalTemplate. Previously radio buttons were sharing templates with checkbox templates. Another changes is that both radios and checkboxes are custom-styled by default.

See CHANGELOG for details.

]]>
0
[news] Yii 2.0.21 Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/news/232/yii-2-0-21 https://www.yiiframework.com/news/232/yii-2-0-21 samdark samdark

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

Version 2.0.21 is a minor release of Yii 2.0 which fixes some bugs, improves database connection performance and adding support for sameSite cookie option for regular and session cookies.

Info: yii\db\Query::select() and addSelect() now normalize the columns when saving them to $this->select, so code that works directly with that property directly may need to be modified.

Thanks to all Yii community members who contribute to the framework, translators who keep documentation translations up to date and community members who answer questions at forums.

There are many active Yii communities so if you need help or want to share your experience, feel free to join them.

A complete list of changes can be found in the CHANGELOG.

]]>
0
[news] Bootstrap 4 extension version 2.0.4 released Tue, 11 Jun 2019 13:28:56 +0000 https://www.yiiframework.com/news/231/bootstrap-4-extension-version-2-0-4-released https://www.yiiframework.com/news/231/bootstrap-4-extension-version-2-0-4-released samdark samdark

Bootstrap 4 extension version 2.0.4 was released. In this release two bugs were fixed.

See CHANGELOG for details.

Note: activateContainer option for Nav introduced in 2.0.3 became obsolete and it has therefore been deleted. Please make sure you are not using it. If you are, remove it from your code.

]]>
0
[news] Imagine extension version 2.2.0 released Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/news/225/imagine-extension-version-2-2-0-released https://www.yiiframework.com/news/225/imagine-extension-version-2-2-0-released samdark samdark

Imagine extension version 2.2.0 was released. The only change in the extension itself is about underlying version of Imagine package used. Now latest version will be installed by default.

See CHANGELOG for details.

]]>
0
[wiki] Nested Set with Yii2 Mon, 01 Apr 2019 07:50:53 +0000 https://www.yiiframework.com/wiki/2549/nested-set-with-yii2 https://www.yiiframework.com/wiki/2549/nested-set-with-yii2 sangprabo sangprabo

The nested set behaviour is an approach to store hierarchical data in relational databases. For example, if we have many categories for our product or items. One category can be a "parent" for other categories, means that one category consists of more than one category. The model can be drawn using a "tree" model. There are other approaches available but what we will learn in this article is specifically the NestedSetsBehavior made by Alexander Kochetov, which utilizing the Modified Preorder Tree Traversal algorithm.

Requirements :

  • Yii2 framework advanced template
  • Yii2 nested sets package

Install the package using composer

It is always recommended to use Composer to install any kind of package or extension for our Yii2-powered project.

$ composer require creocoder/yii2-nested-sets

Create the table

In this article, we will use Category for our model/table name. So we would like to generate the table using our beloved migration tool.

$ ./yii migrate/create create_category_table

We need to modify the table so it contains our desired fields. We also generate three additional fields named position, created_at, and updated_at.

<?php

use yii\db\Migration;

/**
 * Handles the creation for table `category`.
 */
class m160611_114633_create_category extends Migration
{
    /**
     * @inheritdoc
     */
    public function up()
    {
        $this->createTable('category', [
            'id'         => $this->primaryKey(),
            'name'       => $this->string()->notNull(),
            'tree'       => $this->integer()->notNull(),
            'lft'        => $this->integer()->notNull(),
            'rgt'        => $this->integer()->notNull(),
            'depth'      => $this->integer()->notNull(),
            'position'   => $this->integer()->notNull()->defaultValue(0),
            'created_at' => $this->integer()->notNull(),
            'updated_at' => $this->integer()->notNull(),
        ]);
    }

    /**
     * @inheritdoc
     */
    public function down()
    {
        $this->dropTable('category');
    }
}

Then, generate the table using the migration tool.

$ ./yii migrate

If everything is okay, then you could see that a new table named category already exists.

Generate the default CRUD using Gii

To initiate a model, we need to use Gii tool from Yii2. Call the tool from your localhost:8080/gii/model, and fill in the Table Name field with our existing table: category. Fill other fields with appropriate values, and don't forget to give a check to "Generate ActiveQuery" checklist item. This will generate another file that needs to be modified later.

Continue to generate the CRUD for our model with CRUD Generator Tool. Fill in each field with our existing model. After all files are generated, you can see that we already have models, controllers, and views but our work is far from done because we need to modify each file.

Modify models, controllers, and views

The first file we should modify is the model file: Category.

<?php

namespace common\models;

use Yii;
use creocoder\nestedsets\NestedSetsBehavior;

/**
 * This is the model class for table "category".
 *
 * @property integer $id
 * @property string $name
 * @property integer $tree
 * @property integer $lft
 * @property integer $rgt
 * @property integer $depth
 * @property integer $position
 * @property integer $created_at
 * @property integer $updated_at
 */
class Category extends \yii\db\ActiveRecord
{
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'category';
    }

    public function behaviors() {
        return [
            \yii\behaviors\TimeStampBehavior::className(),
            'tree' => [
                'class' => NestedSetsBehavior::className(),
                'treeAttribute' => 'tree',
                // 'leftAttribute' => 'lft',
                // 'rightAttribute' => 'rgt',
                // 'depthAttribute' => 'depth',
            ],
        ];
    }

    public function transactions()
    {
        return [
            self::SCENARIO_DEFAULT => self::OP_ALL,
        ];
    }

    public static function find()
    {
        return new CategoryQuery(get_called_class());
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['name'], 'required'],
            [['position'], 'default', 'value' => 0],
            [['tree', 'lft', 'rgt', 'depth', 'position', 'created_at', 'updated_at'], 'integer'],
            [['name'], 'string', 'max' => 255],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id'         => Yii::t('app', 'ID'),
            'name'       => Yii::t('app', 'Name'),
            'tree'       => Yii::t('app', 'Tree'),
            'lft'        => Yii::t('app', 'Lft'),
            'rgt'        => Yii::t('app', 'Rgt'),
            'depth'      => Yii::t('app', 'Depth'),
            'position'   => Yii::t('app', 'Position'),
            'created_at' => Yii::t('app', 'Created At'),
            'updated_at' => Yii::t('app', 'Updated At'),
        ];
    }

    /**
     * Get parent's ID
     * @return \yii\db\ActiveQuery 
     */
    public function getParentId()
    {
        $parent = $this->parent;
        return $parent ? $parent->id : null;
    }

    /**
     * Get parent's node
     * @return \yii\db\ActiveQuery 
     */
    public function getParent()
    {
        return $this->parents(1)->one();
    }

    /**
     * Get a full tree as a list, except the node and its children
     * @param  integer $node_id node's ID
     * @return array array of node
     */
    public static function getTree($node_id = 0)
    {
        // don't include children and the node
        $children = [];

        if ( ! empty($node_id))
            $children = array_merge(
                self::findOne($node_id)->children()->column(),
                [$node_id]
                );

        $rows = self::find()->
            select('id, name, depth')->
            where(['NOT IN', 'id', $children])->
            orderBy('tree, lft, position')->
            all();

        $return = [];
        foreach ($rows as $row)
            $return[$row->id] = str_repeat('-', $row->depth) . ' ' . $row->name;

        return $return;
    }
}

As you can see, we import the extension using the keyword use:

use creocoder\nestedsets\NestedSetsBehavior;

and I also add the TimeStampBehavior for our additional fields, created_at and updated_at

\yii\behaviors\TimeStampBehavior::className(),

Next : Our modification to CategoryController file is at update, create, and delete function.

<?php

namespace backend\controllers;

use Yii;
use common\models\Category;
use common\models\CategorySearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

/**
 * CategoryController implements the CRUD actions for Category model.
 */
class CategoryController extends Controller
{
    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
        ];
    }

    /**
     * Lists all Category models.
     * @return mixed
     */
    public function actionIndex()
    {
        $searchModel = new CategorySearch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

    /**
     * Displays a single Category model.
     * @param integer $id
     * @return mixed
     */
    public function actionView($id)
    {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Creates a new Category model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        $model = new Category();

        if ( ! empty(Yii::$app->request->post('Category'))) 
        {
            $post            = Yii::$app->request->post('Category');
            $model->name     = $post['name'];
            $model->position = $post['position'];
            $parent_id       = $post['parentId'];

            if (empty($parent_id))
                $model->makeRoot();
            else
            {
                $parent = Category::findOne($parent_id);
                $model->appendTo($parent);
            }

            return $this->redirect(['view', 'id' => $model->id]);
        }

        return $this->render('create', [
                'model' => $model,
            ]);
    }

    /**
     * Updates an existing Category model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     */
    public function actionUpdate($id)
    {
        $model = $this->findModel($id);

        if ( ! empty(Yii::$app->request->post('Category'))) 
        {
            $post            = Yii::$app->request->post('Category');

            $model->name     = $post['name'];
            $model->position = $post['position'];
            $parent_id       = $post['parentId'];

            if ($model->save())            
            {
                if (empty($parent_id))
                {
                    if ( ! $model->isRoot())
                        $model->makeRoot();
                }
                else // move node to other root 
                {
                    if ($model->id != $parent_id)
                    {
                        $parent = Category::findOne($parent_id);
                        $model->appendTo($parent);
                    }
                }

                return $this->redirect(['view', 'id' => $model->id]);
            }
        }

        return $this->render('update', [
            'model' => $model,
        ]);
    }

    /**
     * Deletes an existing Category model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param integer $id
     * @return mixed
     */
    public function actionDelete($id)
    {
        $model = $this->findModel($id);

        if ($model->isRoot())
            $model->deleteWithChildren();
        else 
            $model->delete();

        return $this->redirect(['index']);
    }

    /**
     * Finds the Category model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     * @param integer $id
     * @return Category the loaded model
     * @throws NotFoundHttpException if the model cannot be found
     */
    protected function findModel($id)
    {
        if (($model = Category::findOne($id)) !== null) {
            return $model;
        } else {
            throw new NotFoundHttpException('The requested page does not exist.');
        }
    }
}

As for our views files, we need to remove unnecessary fields from our form, such as the lft, rgt, etc, and add the sophisticated parent field to be a dropdown list. This requires a lot of effort, as you can see on the getTree function on our model.

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;

use common\models\Category;

/* @var $this yii\web\View */
/* @var $model common\models\Category */
/* @var $form yii\widgets\ActiveForm */
?>

<div class="category-form">

    <?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'name')->textInput(['maxlength' => true]) ?>

    <div class='form-group field-attribute-parentId'>
    <?= Html::label('Parent', 'parent', ['class' => 'control-label']);?>
    <?= Html::dropdownList(
        'Category[parentId]',
        $model->parentId,
        Category::getTree($model->id),
        ['prompt' => 'No Parent (saved as root)', 'class' => 'form-control']
    );?>

    </div>

    <?= $form->field($model, 'position')->textInput(['type' => 'number']) ?>

    <div class="form-group">
        <?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

Complete files can be found at my GitHub page: https://github.com/prabowomurti/learn-nested-set

The screencast (subtitled English) here : https://www.youtube.com/watch?v=MjJEjF1arHs

]]>
0
[wiki] Events registration examples Mon, 11 Mar 2019 14:04:14 +0000 https://www.yiiframework.com/wiki/2548/events-registration-examples https://www.yiiframework.com/wiki/2548/events-registration-examples minitia82 minitia82

Register an event handler at Object-Level

e.g inside the init method of a Model

// this should be inside your model class. For example User.php
public function init(){
  $this->on(self::EVENT_NEW_USER, [$this, 'sendMail']);
  $this->on(self::EVENT_NEW_USER, [$this, 'notification']);
  // first parameter is the name of the event and second is the handler. 
  // For handlers I use methods sendMail and notification
  // from $this class.
  parent::init(); // DON'T Forget to call the parent method.
}

from https://stackoverflow.com/questions/28575636/how-to-use-events-in-yii2

Register an event handler at Class-Level

To register event handlers at Class-Level a good place can be inside the bootstrap process.

So, you can put the registration code as

Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
    Yii::debug(get_class($event->sender) . ' is inserted');
});

in a php file like the bootstrap.php used in Advanced-Template or through configuration, with your custom component for example

see docs

(https://www.yiiframework.com/doc/guide/2.0/en/structure-applications#bootstrap or https://www.yiiframework.com/doc/guide/2.0/en/structure-extensions#bootstrapping-classes)

]]>
0
[wiki] (draft) Understanding Yii 3 Sun, 30 Dec 2018 21:44:55 +0000 https://www.yiiframework.com/wiki/2547/draft-understanding-yii-3 https://www.yiiframework.com/wiki/2547/draft-understanding-yii-3 machour machour

Understanding Yii 3

  1. Introduction
  2. Changes overview
  3. Yii 3 composer packages
  4. Running your first Yii 3 powered application

Since this Wiki page is getting bigger and bigger, I decided to document things in a Yii 3 project instead.

Project source can be found at https://github.com/machour/yii3-kitchen-sink Live web site: https://yii3.idk.tn/

Follow the repo/website to get fresher informations, or better yet, pull the project and run it by yourself to get acquainted with Yii3

Introduction

This document is intended for an audience already familiar with Yii2. It's meant to bring together all information related to Yii 3 in one place to make it easier to get on track.

Yii 3 is the second major rewrite of the Yii framework.

Originally started in the 2.1 branch, it was later decided to switch to the 3.X series because of all the backward compatibility breakage. Starting with 3.0, Yii will follow the Sementic Versionning.

This rewrite addresses a lot of issues Yii 2 suffered from, like the framework being too coupled with jQuery, bower, bootstrap. [TODO: add more grieffs about Yii2]

Changes overview

Here are the main changes in Yii 3. You can check the complete CHANGELOG for an exhaustive list.

Source code splitting

The framework source code have been split into several packages, and at its core level, Yii no longer makes assumptions about your development stack, or the features you will be using.

This enable you to cherry pick the packages you need to compose your application.

This re-organisation is also a great news for maintainance, as these packages will be released separately, thus allowing more frequent updates.

Autoloading

The custom PHP class autoloader have been removed in favor of Composer's PSR-4 implementation. This means that in order for Yii to see your classes, you will have to explicitly register your namespace in composer.json. We will see an example later.

PSR compatibility

Yii 3 takes some positive steps following the PHP-FIG recommendations, by implementing the following PSRs:

  • Logging is now compliant with PSR-3
  • Caching is now compliant with PSR-16
  • Dependency Injection is now compliant with PSR-11
Application configuration

If you've ever installed an extension using Yii 2, you may/certainly have found yourself on the extension README file, looking for the chunk of configuration to copy/paste in your own config/main.php file.

This can often lead to:

  • a huge configuration file (which you may have decided to split into smaller files)
  • non-trivials configurations update when a new version of the extension is realeased with new/changed configurations options.

Yii 3 takes another approach. Every package bundle its own configuration, and will probably work out of the box. And you may override them, if you need to, from your configuration file.

This is all done by leveraging the hiqdev/composer-config-plugin composer plugin, which takes care of scanning & merging all the configurations when you run composer dump-autoload (also know as composer du).

You can read Yii2 projects alternative organization for an in-depth explanation of the motivation behind hiqdev/composer-config-plugin.

Packages authors will have the responsibility to avoid introducing BC breaks, by adopting a strict sementical versionning.

Dependencies injection

[TODO]

Yii 3 composer packages

Here are the new packages introduced in Yii 3, which can be found in this official list.

Let's introduce them briefly:

The Framework

This is the new kernel of Yii. It defines the base framework and its core features like behaviors, i18n, mail, validation..

You will rarely want to directly install yiisoft/yii-core. Instead, you will install one or more of the following:

This three packages, considered as Extensions, are responsible for implementing the basic functionnalities of each "channel" they refer to:

  • yii-console implements all that you need to build a console application (the base Controller for commands, the Command helper, ..)
  • yii-web implements all that you need to build a web application (Assets management, Sessions, Request handling ..)
  • yii-rest implements all that you need to build a REST interface (ActiveController, ..)
Librairies

In Yii 3, libraries do not depend on Yii and are meant to be usable outside the framework. Their package name is yiisoft/something without yii-prefix.

Drivers for yiisoft/db

The various drivers for DB have also been separated into packages:

Extensions

Extensions depends (at least) on yii-core. Aside from the 3 extensions already encountered above (yii-console, yii-web, yii-api), these packages are available

Development
View rendering engines
Data rendering
JS & CSS Frameworks integration
Widgets
Misc
Yii project template and application bases

This is a very basic Yii project template, that you can use to start your development.

You will probably want to pick one or more of these three starters to install in your project next:

Let's try running the web base template in the next section.

Running your first Yii 3 powered application

Let's try running a web application using Yii 3, and the provided project template.

Installing the project template
composer create-project --prefer-dist --stability=dev yiisoft/yii-project-template myapp
cd myapp

Here's the created structure:

.
├── LICENSE
├── README.md
├── composer.json
├── composer.lock
├── config
│   ├── common.php
│   └── params.php
├── docker-compose.yml
├── hidev.yml
├── public
│   ├── assets
│   ├── favicon.ico
│   ├── index.php
│   └── robots.txt
├── runtime
└── vendor

You won't be able to start the web server right away using ./vendor/bin/yii serve, as it will complain about not knowing the "app" class.

In fact, this project template only introduce the bare minimum in your application: Caching, Dependencies injection, and Logging. The template doesn't make an assumption about the kind of application you're building (web, cli, api).

You could start from scratch using this bare template, select the extensions & packages you want to use and start developing, or you can pick one of the three starters provided.

Installing the web starter

Since we're doing a web application, we will need an asset manager. We can pick either one of those:

  • Asset-packagist & composer-merge-plugin (requires only PHP)
  • Foxy (requires npm or yarn)

Let's go with foxy (personal taste since composer is so slow from Tunisia):

composer require "foxy/foxy:^1.0.0"

We can now install the yii-base-web starter and run our application:

composer require yiisoft/yii-base-web
vendor/bin/yii serve

By visiting http://localhost:8080/, you should now see something like this:

50153967-44a6af00-02c8-11e9-9914-ceb463065cdf.png

Checking back our project structure, nothing really changed, aside from the creation of these three entries:

  • node_modules/
  • package-lock.json
  • package.json

So where do what we see in the browser comes from ?

Exploring yiisoft/yii-base-web structure:

If you explore the folder in vendor/yiisoft/yii-base-web, you will see that the template is in fact a project itself, with this structure:

.
├── LICENSE.md
├── README.md
├── composer.json
├── config
│   ├── common.php
│   ├── console.php
│   ├── env.php
│   ├── messages.php
│   ├── params.php
│   └── web.php
├── phpunit.xml.dist
├── public
│   └── css
│       └── site.css
├── requirements.php
├── runtime
└── src
    ├── assets
    │   └── AppAsset.php
    ├── commands
    │   └── HelloController.php
    ├── controllers
    │   └── SiteController.php
    ├── forms
    │   ├── ContactForm.php
    │   └── LoginForm.php
    ├── mail
    │   └── layouts
    ├── messages
    │   ├── et
    │   ├── pt-BR
    │   ├── ru
    │   └── uk
    ├── models
    │   └── User.php
    ├── views
    │   ├── layouts
    │   └── site
    └── widgets
        └── Alert.php

The folders and files should make sense to you if you already developed applications using Yii2 and the basic template.

]]>
0
[wiki] Batch Gridview data ajax send splitted in chunks displaying bootstrap Progress bar Sat, 24 Nov 2018 10:48:47 +0000 https://www.yiiframework.com/wiki/2546/batch-gridview-data-ajax-send-splitted-in-chunks-displaying-bootstrap-progress-bar https://www.yiiframework.com/wiki/2546/batch-gridview-data-ajax-send-splitted-in-chunks-displaying-bootstrap-progress-bar toaster toaster

The scenario in which this wiki can be useful is when you have to send an (huge) array of model ids and perform a time consuming computation with it like linking every model to other models. The idea is to split the array into smaller arrays and perform sequential ajax requests, showing the calculation progress using a Bootstrap Progress bar.

I have created a Country model and generated the CRUD operations using Gii. The model class look like this:

namespace app\models;
use Yii;
use yii\helpers\ArrayHelper;

/**
 * This is the model class for table "country".
 *
 * @property string $code
 * @property string $name
 * @property int $population
 *
 */
class Country extends \yii\db\ActiveRecord {

    /**
     * {@inheritdoc}
     */
    public static function tableName() {
        return 'country';
    }

    /**
     * {@inheritdoc}
     */
    public function rules() {
        return [
            [['code', 'name'], 'required'],
            [['population'], 'integer'],
            [['code'], 'string', 'max' => 3],
            [['name'], 'string', 'max' => 52],
            [['code'], 'unique'],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels() {
        return [
            'code' => 'Code',
            'name' => 'Name',
            'population' => 'Population',
        ];
    }
    /**
     * 
     * @return array
     */
    public static function getCodes(){
        return array_keys(ArrayHelper::map(Country::find()->select('code')->asArray()->all(), 'code', 'code'));
    }
}

I have also created another model that will take care to validate the ids and perform the time consuming calculation through the process() function. (in this example I just use a sleep(1) that will wait for one second for each element of the $codes array). I also want to keep track of the processed models, incrementing the $processed class attribute.

<?php

namespace app\models;

use app\models\Country;

/**
 * Description of BatchProcessForm
 *
 * @author toaster
 */
class BatchProcessForm extends \yii\base\Model {

    /**
     * The codes to process
     * @var string
     */
    public $codes;

    /**
     * The number of codes processed
     * @var integer
     */
    public $processed = 0;

    /**
     * @return array the validation rules.
     */
    public function rules() {
        return [
            ['codes', 'required'],
            ['codes', 'validateCodes'],
        ];
    }

    /**
     * Check whether codes exists in the database
     * @param type $attribute
     * @param type $params
     * @param type $validator
     */
    public function validateCodes($attribute, $params, $validator) {
        $input_codes = json_decode($this->$attribute);
        if (null == $input_codes || !is_array($input_codes)) {
            $this->addError($attribute, 'Wrong data format');
            return;
        }
        $codes = Country::getCodes();
        if (!array_intersect($input_codes, $codes) == $input_codes) {
            $this->addError($attribute, 'Some codes selected are not recognized');
        }
    }

    /**
     * Process the codes
     * @return boolean true if everything goes well
     */
    public function process() {
        if ($this->validate()) {
            $input_codes = json_decode($this->codes);
            foreach ($input_codes as $code) {
                sleep(1);
                $this->processed++;
            }
            return true;
        }
        return false;
    }

}

The code for the controller action is the following:

/**
 * Process an array of codes
 * @return mixed
 * @throws BadRequestHttpException if the request is not ajax
 */
public function actionProcess(){
    if(Yii::$app->request->isAjax){
        Yii::$app->response->format = Response::FORMAT_JSON;
        $model = new BatchProcessForm();
        if($model->load(Yii::$app->request->post()) && $model->process()){
            return ['result' => true, 'processed' => $model->processed];
        }
        return ['result' => false, 'error' => $model->getFirstError('codes')];
    }
    throw new \yii\web\BadRequestHttpException;
}

In my index.php view I have added a CheckboxColumn as first column of the Gridview that allows, out of the box, to collect the ids of the models selected via Javascript (in this case the values of the code attribute). I have also added a button-like hyperlink tag to submit the collected data (with id batch_process) and a Bootstrap Progress bar inside a Modal Window. The code of my view is the following:

<?php

use yii\helpers\Html;
use yii\grid\GridView;
use yii\bootstrap\Modal;

/* @var $this yii\web\View */
/* @var $searchModel app\models\CountrySearch */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = 'Countries';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="country-index">

    <h1><?= Html::encode($this->title) ?></h1>
    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>

    <p>
        <?= Html::a('Create Country', ['create'], ['class' => 'btn btn-success']) ?>
        <?= Html::a('Batch Process', ['process'], ['class' => 'btn btn-info', 'id' => 'batch_process']) ?>
    </p>

    <?=
    GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,
        'options' => [
            'id' => 'country-index'
        ],
        'columns' => [
            ['class' => 'yii\grid\CheckboxColumn'],
            'code',
            'name',
            'population',
            ['class' => 'yii\grid\ActionColumn'],
        ],
    ]);
    ?>
</div>

<?php Modal::begin(['header' => '<h5 id="progress">0% Complete</h5>', 'id' => 'progress-modal', 'closeButton' => false]); ?>

<?=
yii\bootstrap\Progress::widget([
    'percent' => 0,
     'options' => ['class' => 'progress-success active progress-striped']
]);
?>

<?php Modal::end(); ?>

<?php $this->registerJsFile('@web/js/main.js', ['depends' => [\app\assets\AppAsset::class]]); ?>

The Javascript file that split in chunks the array and send each chunk sequentially is main.js. Although I have registered the Javascript file using registerJsFile() method I highly recommend to better handle and organize js files using Asset Bundles. Here is the code:


function updateProgressBar(percentage) {
    var perc_string = percentage + '% Complete';
    $('.progress-bar').attr('aria-valuenow', percentage);
    $('.progress-bar').css('width', percentage + '%');
    $('#pb-small').text(perc_string);
    $('#progress').text(perc_string);
}

function disposeProgressBar(message) {
    alert(message);
    $('#progress-modal').modal('hide');
}

function showProgressBar() {
    var perc = 0;
    var perc_string = perc + '% Complete';
    $('.progress-bar').attr('aria-valuenow', perc);
    $('.progress-bar').css('width', perc + '%');
    $('#pb-small').text(perc_string);
    $('#progress').text(perc_string);
    $('#progress-modal').modal('show');
}

function batchSend(set, iter, take, processed) {
    var group = iter + take < set.length ? iter + take : set.length;
    var progress = Math.round((group / set.length) * 100);
    var dataObj = [];
    for (var i = iter; i < group; i++) {
        dataObj.push(set[i]);
    }
    iter += take;
    $.ajax({
        url: '/country/process', ///?r=country/process
        type: 'post',
        data: {'BatchProcessForm[codes]': JSON.stringify(dataObj)},
        success: function (data) {
            if (data.result) {
                updateProgressBar(progress);
                processed += data.processed;
                if (progress < 100) {
                    batchSend(set, iter, take, processed);
                } else {
                    var plural = processed == 1 ? 'country' : 'countries';
                    disposeProgressBar(processed + ' ' + plural + ' correctly processed');
                }
                return true;
            }
            disposeProgressBar(data.error);
            return false;
        },
        error: function () {
            disposeProgressBar('Server error, please try again later');
            return false;
        }
    });
}

$('#batch_process').on('click', function (e) {
    e.preventDefault();
    var keys = $('#country-index').yiiGridView('getSelectedRows');
    if (keys.length <= 0) {
        alert('Select at least one country');
        return false;
    }
    var plural = keys.length == 1 ? 'country' : 'countries';
    if (confirm(keys.length + ' ' + plural + ' selected.. continue?')) {
        showProgressBar();
        batchSend(keys, 0, 5, 0);
    }
});

The first three functions take care to show, update and hide the progress bar inside the modal window, while the batchSend function perform the array split and, using recursion, send the data through post ajax request, encoding the array as JSON string and calling itself until there is no more chunks to send. The last lines of code bind the click event of the #batch_process button checking if at least one row of Gridview has been selected. The number of elements on each array chunk can be set as the third argument of the batchSend function (in my case 5), you can adjust it accordingly. The first parameter is the whole array obtained by the yiiGridView('getSelectedRows') function. The final result is something like this:

batch_send1.gif

...looks cool, isn't it?

]]>
0
[wiki] Using multiple models in an identity Tue, 29 Jan 2019 23:11:01 +0000 https://www.yiiframework.com/wiki/2545/using-multiple-models-in-an-identity https://www.yiiframework.com/wiki/2545/using-multiple-models-in-an-identity samdark samdark

Let's assume we have two models: Customer and Supplier and we want both to log in. Yii is quite flexible when it comes to authentication and authorization so it's possible.

First of all, Yii assumes that there's a single type of user component used at once. Still, we're able to create a universal Identity that works with both customers and suppliers.

So we create models/Identity.php:

final class Identity implements IdentityInterface
{
    const TYPE_CUSTOMER = 'customer';
    const TYPE_SUPPLIER = 'supplier';

    const ALLOWED_TYPES = [self::TYPE_CUSTOMER, self::TYPE_SUPPLIER];

    private $_id;
    private $_authkey;
    private $_passwordHash;

    public static function findIdentity($id)
    {
        $parts = explode('-', $id);
        if (\count($parts) !== 2) {
            throw new InvalidCallException('id should be in form of Type-number');
        }
        [$type, $number] = $parts;

        if (!\in_array($type, self::ALLOWED_TYPES, true)) {
            throw new InvalidCallException('Unsupported identity type');
        }

        $model = null;
        switch ($type) {
            case self::TYPE_CUSTOMER:
                $model = Customer::find()->where(['id' => $number])->one();
                break;
            case self::TYPE_SUPPLIER:
                $model = Supplier::find()->where(['id' => $number])->one();
                break;
        }

        if ($model === null) {
            return false;
        }


        $identity = new Identity();
        $identity->_id = $id;
        $identity->_authkey = $model->authkey;
        $identity->_passwordHash = $model->password_hash;
        return $identity;
    }

    public static function findIdentityByAccessToken($token, $type = null)
    {
        $model = Customer::find()->where(['token' => $token])->one();
        if (!$model) {
            $model = Supplier::find()->where(['token' => $token])->one();
        }

        if (!$model) {
            return false;
        }

        if ($model instanceof Customer) {
            $type = self::TYPE_CUSTOMER;
        } else {
            $type = self::TYPE_SUPPLIER;
        }

        $identity = new Identity();
        $identity->_id = $type . '-' . $model->id;
        $identity->_authkey = $model->authkey;
        $identity->_passwordHash = $model->password_hash;
        return $identity;
    }

    public function validatePassword($password)
    {
        return password_verify($password, $this->_passwordHash);
    }

    public static function findIdentityByEmail($email)
    {
        $model = Customer::find()->where(['email' => $email])->one();
        if (!$model) {
            $model = Supplier::find()->where(['email' => $email])->one();
        }

        if (!$model) {
            return false;
        }

        if ($model instanceof Customer) {
            $type = self::TYPE_CUSTOMER;
        } else {
            $type = self::TYPE_SUPPLIER;
        }

        $identity = new Identity();
        $identity->_id = $type . '-' . $model->id;
        $identity->_authkey = $model->authkey;
        $identity->_passwordHash = $model->password_hash;
        return $identity;
    }

    public function getId()
    {
        return $this->_id;
    }

    public function getAuthKey()
    {
        return $this->_authkey;
    }

    public function validateAuthKey($authKey)
    {
        return $this->getAuthKey() === $authKey;
    }
}

In the above we assume that our ids are like customer-23 or supplier-34. When we need to get identity instance we split the id by - and getting both type and integer id for the model corresponding to that type.

Having identity we can tell Yii to use it via config/main.php:

[
    // ...
    'components' => [
        // ...
        'user' => [
            'identityClass' => 'app\models\Identity',
            'enableAutoLogin' => true,
        ],
    ],
],

The only thing left is to adjust models\LoginForm.php:

class LoginForm extends Model
{
    // ...
    
    public function getUser()
    {
        if ($this->_user === false) {
            $this->_user = Identity::findIdentityByEmail($this->username);
        }

        return $this->_user;
    }
}

That's it. Now you can log in using both models.

]]>
0
[wiki] Update and Delete buttons on Breadcrumb Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/wiki/2544/update-and-delete-buttons-on-breadcrumb https://www.yiiframework.com/wiki/2544/update-and-delete-buttons-on-breadcrumb adinugro adinugro

The definition of breadcrumbs according to its documentation is as follow: Breadcrumbs displays a list of links indicating the position of the current page in the whole site hierarchy.

We can define the breadcrumbs easily by adding these lines.

$this->title = $model->formNo;
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Supplier receiving'), 'url' => ['index', 'type' => $model->type]];
$this->params['breadcrumbs'][] = ['label' => $this->title, 'url' => ['view', 'id' => $model->id]];

Reading the documentation, I encountered the template keyword. I was excited about the possibility to add buttons into breadcrumbs. Add these lines and you would have buttons on the right side of the breadcrumb.

$this->title = $model->formNo;
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Supplier receiving'), 'url' => ['index', 'type' => $model->type]];
$this->params['breadcrumbs'][] = ['label' => $this->title, 'url' => ['view', 'id' => $model->id]];
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Delete'), 'template' =>
    Html::tag('span', Html::a(Html::icon('glyphicon glyphicon-trash white') . ' ' . Yii::t('app', 'Delete'), Url::to(['delete', 'id' => $model->id]), [
                'class' => 'btn btn-xs btn-danger',
                'title' => Yii::t('app', 'Delete'),
                'data-pjax' => '0',
                'data-method' => 'POST',
                'data-confirm' => Yii::t('app', 'Are you sure you want to delete this supplier receiving?'),
                    ]
            ), ['class' => 'pull-right'])];
$this->params['breadcrumbs'][] = ['label' => Yii::t('app', 'Update'), 'template' => Html::tag('span', Html::a(
                    Html::icon('glyphicon glyphicon-pencil') . ' ' . Yii::t('app', 'Update'), Url::to(['update', 'id' => $model->id, 'inview' => 1]), [
                'class' => 'btn btn-xs btn-warning',
                'title' => Yii::t('app', 'Update'),
                'role' => 'modal-remote',
                'data-toggle' => 'tooltip',
                    ]
            ), ['class' => 'pull-right', 'style' => 'margin-right: 5px;'])];

Actually you can use this line to define the template, but $links means the full link. A suggestion to the developer is to make the $url and $label variables to be available like $links, so that we can make the template more flexible and meaningful than above codes.

FYI,

  1. I use ajaxcrud extension, so that the update link has 'role' => 'modal-remote' to allow the update process taken place on the modal window. I added a inview parameter to distinguish the update from index or view. Both actions will be called using ajax request and will show the form on the modal, but the index update will redirect to index and refresh gridview while in the view, it should redirect to the view.
  2. On the template, I used span over li to make ' / ' character not appear on the links buttons.

A simple tip to make the view layout efficient.

]]>
0
[wiki] When to use Active Record Sun, 22 Sep 2019 05:45:36 +0000 https://www.yiiframework.com/wiki/2541/when-to-use-active-record https://www.yiiframework.com/wiki/2541/when-to-use-active-record samdark samdark

When to use Active Record is a common question among developers, Yii and overall.

I have about 500K records in my DB tables and each query there are 2 or 3 joins. I was getting data via AR, about a hundred records a time and noticed that using createCommand consumes less memory and CPU. I think with DAO instead of AR it will be faster.

It is true that Active Record consumes memory for storing objects and CPU cycles for instantiate these objects.

Is AR bad? It it for small projects only? We have lots of inserts, about 5000 records an hour and we're using AR for that. Should we re-write?

AR is a pleasure to use when you're managing not that many records at the same time. CRUD is very easy with it. Yii 2 dirty attribute support (only what was modified is saved) off-loads database and mitigates many parallel editing conflicts. If you don't have complex logic in your app and you don't need entity abstractions, AR is an ideal choice.

AR is OK for queries not too complicated when they return no more than a hundred objects. Yes, it is faster and less memory consuming to use query builder or asArray() but working with arrays is significantly less convenient.

For complex queries, such as aggregates or reports, AR isn't recommended. These are easier to express with query builder or SQL. Same goes for import and export routines.

]]>
0
[wiki] Getting information from the current locale Thu, 09 Aug 2018 18:56:33 +0000 https://www.yiiframework.com/wiki/2540/getting-information-from-the-current-locale https://www.yiiframework.com/wiki/2540/getting-information-from-the-current-locale CeBe CeBe

Yii 2.0 comes with a formatter component to format dates, numbers, and other values for international users according to their locale. This is very useful for displaying data. When working with incoming data or when using enhanced input methods like the MaskedInput widget you sometimes need to access the symbols used by the formatter to generate a pattern or parse the input.

The Yii formatter does not have methods to access this data, it relies on the PHP intl extension for formatting. If you want to access the formatting symbols you need to work with intl directly.

Getting decimal and thousand separator

$locale = 'de_DE';

$formatter = new \NumberFormatter($locale,\NumberFormatter::DECIMAL);

$decimalSeparator = $formatter->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
$thousandSeparator = $formatter->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL);

There are more symbols than shown above, for the full list of symbols see the list of NumberFormatter constants in the php manual.

Getting a currency symbol

Getting the currency symbol is a bit more complicated if you do not want the symbol of the default currency of a locale, but another currency:

$locale = 'de_DE'; // get the currency symbol of Germanys default currency EUR = "€"
$locale = 'de_DE@currency=USD'; // get the currency symbol of USD in German locale = "$"

$formatter = new \NumberFormatter($locale, \NumberFormatter::CURRENCY);

$currencySymbol = $formatter->getSymbol(\NumberFormatter::CURRENCY_SYMBOL);

Note, that the NumberFormatter is instantiated with the CURRENCY constant instead of DECIMAL here.

Since Yii 2.0.14 Yii has this method built-in in the Locale class.

]]>
0
[wiki] What SQL-Statement creates yii? Fri, 27 Jul 2018 11:28:13 +0000 https://www.yiiframework.com/wiki/2539/what-sql-statement-creates-yii https://www.yiiframework.com/wiki/2539/what-sql-statement-creates-yii Necip Necip

The usual way to find out what Yii has created for an SQL query is to mutilate the SQL in the sourcecode and call the program again so that the SQL statement with errors is displayed. Or you can use the SQL logger, which must be switched on and off each time and logs all SQL statements, which leads to an enormous slowdown in program execution and decelerates your workflow.

These all is not necessary if you use XDebug and place a breakpoint after the function "getCommandBuilder" in the CActiveRecord.php and take a closer look at the return value in $command.

This database access is created in yii:

yii-sql11.png?w=474

This code is called by the yii framework

yii-sql21.png?w=474

getCommandBuilder returns this data structure with the generated SQL statement:

yii-sql32.png?w=474

Path to CActiveRecord.php

C:\xampp\htdocs\your_project\yii\framework\db\ar\CActiveRecord.php

]]>
0
[wiki] How to organize Design "things" in Yii 2 (themes and layout) Thu, 23 Aug 2018 17:32:30 +0000 https://www.yiiframework.com/wiki/2538/how-to-organize-design-things-in-yii-2-themes-and-layout https://www.yiiframework.com/wiki/2538/how-to-organize-design-things-in-yii-2-themes-and-layout olissongs olissongs
  1. Via "theming"
  2. Using layouts
  3. Both
  4. UseCase one
  5. UseCase two

Sometimes the App needs a nicer look & feel, so its necessary to organize the assets for this and Yii can help a lot to make it easy. In this article I provide tips for handling multiple "Designs". I use these three features:

  • AssetBundle
  • Layouts
  • Themes

What do you need for desingning your website:

  • CSS files
  • JS files
  • some Images or other media.

Lets call it "DesignAssets"

What Yii needs:

  • one or more Layout files
  • the view files
  • AssetBundle set in the layout-file

Lets call it "DesignTemplates".

So how to bundle these and where is the best place to put them in your application directory?

Via "theming"

  • myYiiApp
    • ...
    • designs
      • myDesign1
        • put here all your "DesignTemplates" (AssetBundle,layout, and view folder/files, when using themes)

Using layouts

  • myYiiApp
    • ...
    • views
      • layouts
        • myDesign1.php (layout file)
      • ...

Both

  • myYiiApp

    • ...
    • web

      • designs
        • myDesign1
          • put here all your "DesignAssets" (css, js, img, etc.)
    • ...

So you can work with the default security file-rights for the correct purpose.

UseCase one

Write an App and distribute it to some Customer. Here can it be necessary that every customer wants a personal design.

Solution: Using themes

you config in your web.php or main.php (advanced template) whats documented here

if you need special "DesignAssets"

put your "DesignAssets" und the web directory myYiiApp/web/designs/myDesign1/css and js and img folders

customize your myYiiApp/designs/myDesign1/assets/MyDesignAsset.php

and your layout file myYiiApp/designs/myDesign1/layout/main.php

thats it.

UseCase two

you need several designs for e.g. controllers. so my remmmendation is using layouts, because easy switching in controller action.

Solution with layouts

there is no need to configure anything in the config files

if you need special "DesignAssets"

put your "DesignAssets" und the web directory myYiiApp/web/designs/myDesign1/css and js and img folders

create and customize your myYiiApp/assets/MyDesignAsset.php

and your layout file myYiiApp/views/layout/mydesign1.php

in your controller action set your layout.

public function actionIndex() {
    $this->layout = 'mydesign1';
}

may it helps your start with designing Yii.

]]>
0
[wiki] An alternative way to ElasticSearch Sun, 12 Aug 2018 07:49:50 +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-Plugin 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
[wiki] Pjax GridView: refresh page after delete Tue, 24 Jul 2018 14:11:51 +0000 https://www.yiiframework.com/wiki/867/pjax-gridview-refresh-page-after-delete https://www.yiiframework.com/wiki/867/pjax-gridview-refresh-page-after-delete 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
[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
[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
[wiki] Yii2 RESTful API with OAuth 2.0 Thu, 08 Nov 2018 00:08:15 +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://developers.yii2.nintriva.net/

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

Similar API Implementation in NodeJs,Laravel &GoLang

Expressjs 4.15/Mysql RESTful API with OAuth2

Expressjs 4.15/MongoDb RESTful API with OAuth2

Laravel 5.5 Lumen 5.5/Mysql RESTful API with OAuth2

GoLang/MongoDb Microservice with OAuth2

Linkedin Post1

Linkedin Post2

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