Live News for Yii Framework News, fresh extensions and wiki articles about Yii framework. Tue, 26 Mar 2019 02:03:37 +0000 Zend_Feed_Writer 2 (http://framework.zend.com) https://www.yiiframework.com/ [extension] mihaildev/yii2-ckeditor Tue, 26 Mar 2019 02:03:35 +0000 https://www.yiiframework.com/extension/mihaildev/yii2-ckeditor https://www.yiiframework.com/extension/mihaildev/yii2-ckeditor mihail_dev mihail_dev

CKEditor Расширение для Yii 2

  1. Установка
  2. Использование
  3. Полезные ссылки

CKEditor — свободный WYSIWYG-редактор, который может быть использован на веб-страницах.

Установка

Удобнее всего установить это расширение через composer.

Либо запустить

php composer.phar require --prefer-dist mihaildev/yii2-ckeditor "*"

или добавить

"mihaildev/yii2-ckeditor": "*"

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

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

use mihaildev\ckeditor\CKEditor;
use yii\helpers\Html;

CKEditor::widget([
    'editorOptions' => [
        'preset' => 'full', //разработанны стандартные настройки basic, standard, full данную возможность не обязательно использовать
        'inline' => false, //по умолчанию false
    ]
]);

//или c ActiveForm

echo $form->field($post, 'content')->widget(CKEditor::className(),[
    'editorOptions' => [
        'preset' => 'full', //разработанны стандартные настройки basic, standard, full данную возможность не обязательно использовать
        'inline' => false, //по умолчанию false
    ],
]);

Полезные ссылки

CKEditor Api - http://docs.ckeditor.com/

CKEditor Примеры - http://nightly.ckeditor.com/

Файл Менеджер ElFinder - https://github.com/MihailDev/yii2-elfinder

]]>
0
[extension] mihaildev/yii2-elfinder Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/mihaildev/yii2-elfinder https://www.yiiframework.com/extension/mihaildev/yii2-elfinder mihail_dev mihail_dev

ElFinder Расширение для Yii 2

  1. Поддерживаемые хранилища
  2. Установка
  3. Настройка
  4. Настройка callback-ов для событий
  5. Настройка Плагинов
  6. Использование
  7. Использование при работе с PathController
  8. CKEditor
  9. Проблемы

ElFinder — файловый менеджер для сайта.

Поддерживаемые хранилища

mihaildev/yii2-elfinder-flysystem - https://github.com/MihailDev/yii2-elfinder-flysystem/

    Local
    Azure
    AWS S3 V2
    AWS S3 V3
    Copy.com
    Dropbox
    FTP
    GridFS
    Memory
    Null / Test
    Rackspace
    ReplicateAdapter
    SFTP
    WebDAV
    PHPCR
    ZipArchive

Установка

Удобнее всего установить это расширение через composer.

Либо запустить

php composer.phar require --prefer-dist mihaildev/yii2-elfinder "*"

или добавить

"mihaildev/yii2-elfinder": "*"

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

Настройка

'controllerMap' => [
        'elfinder' => [
            'class' => 'mihaildev\elfinder\Controller',
            'access' => ['@'], //глобальный доступ к фаил менеджеру @ - для авторизорованных , ? - для гостей , чтоб открыть всем ['@', '?']
            'disabledCommands' => ['netmount'], //отключение ненужных команд https://github.com/Studio-42/elFinder/wiki/Client-configuration-options#commands
            'roots' => [
                [
                    'baseUrl'=>'@web',
                    'basePath'=>'@webroot',
                    'path' => 'files/global',
                    'name' => 'Global'
                ],
                [
                    'class' => 'mihaildev\elfinder\volume\UserPath',
                    'path'  => 'files/user_{id}',
                    'name'  => 'My Documents'
                ],
                [
                    'path' => 'files/some',
                    'name' => ['category' => 'my','message' => 'Some Name'] //перевод Yii::t($category, $message)
                ],
                [
                    'path'   => 'files/some',
                    'name'   => ['category' => 'my','message' => 'Some Name'], // Yii::t($category, $message)
                    'access' => ['read' => '*', 'write' => 'UserFilesAccess'] // * - для всех, иначе проверка доступа в даааном примере все могут видет а редактировать могут пользователи только с правами UserFilesAccess
                ]
            ],
            'watermark' => [
            		'source'         => __DIR__.'/logo.png', // Path to Water mark image
                     'marginRight'    => 5,          // Margin right pixel
                     'marginBottom'   => 5,          // Margin bottom pixel
                     'quality'        => 95,         // JPEG image save quality
                     'transparency'   => 70,         // Water mark image transparency ( other than PNG )
                     'targetType'     => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field )
                     'targetMinPixel' => 200         // Target image minimum pixel size
            ]
        ]
    ],
'controllerMap' => [
        'elfinder' => [
			'class' => 'mihaildev\elfinder\PathController',
			'access' => ['@'],
			'root' => [
				'path' => 'files',
				'name' => 'Files'
			],
			'watermark' => [
						'source'         => __DIR__.'/logo.png', // Path to Water mark image
						 'marginRight'    => 5,          // Margin right pixel
						 'marginBottom'   => 5,          // Margin bottom pixel
						 'quality'        => 95,         // JPEG image save quality
						 'transparency'   => 70,         // Water mark image transparency ( other than PNG )
						 'targetType'     => IMG_GIF|IMG_JPG|IMG_PNG|IMG_WBMP, // Target image formats ( bit-field )
						 'targetMinPixel' => 200         // Target image minimum pixel size
			]
		]
    ],

Разница между PathController и Controller в том что PathController работает только с одной папкой также имеет доп возможность передать в запросе на открытие под деритории

На данный момент реализованно использование только LocalFileSystem хранилища (mihaildev\elfinder\volume\Local и mihaildev\elfinder\volume\UserPath) для использования остальных вам прийдётся всё настраивать через mihaildev\elfinder\volume\Base также добавленно расширение https://github.com/MihailDev/yii2-elfinder-flysystem/ это дополнение позволяет интегрировать Flysystem хранилища такие как

Local
Azure
AWS S3 V2
AWS S3 V3
Copy.com
Dropbox
FTP
GridFS
Memory
Null / Test
Rackspace
ReplicateAdapter
SFTP
WebDAV
PHPCR
ZipArchive

Настройка callback-ов для событий

'controllerMap' => [
        'elfinder' => [
            ...            
            'managerOptions' => [
                ...
                'handlers' => [
                    'select' => 'function(event, elfinderInstance) {
                                    console.log(event.data);
                                    console.log(event.data.selected);
                                }', 
                    'open' => 'function(event, elfinderInstance) {...}',
                ],
                ...
            ],
            ...
        ]
    ],

список событий - https://github.com/Studio-42/elFinder/wiki/Client-event-API#event-list

Настройка Плагинов

Изза сложной настройки была переделанна работа плагинов но возможность использовать старые плагины присутствует `php 'controllerMap' => [

    'elfinder' => [
        'class' => 'mihaildev\elfinder\Controller',
        //'plugin' => ['\mihaildev\elfinder\plugin\Sluggable'],
        'plugin' => [
            [
                'class'=>'\mihaildev\elfinder\plugin\Sluggable',
                'lowercase' => true,
                'replacement' => '-'
            ]
         ],
         'roots' => [
                         [
                             'baseUrl'=>'@web',
                             'basePath'=>'@webroot',
                             'path' => 'files/global',
                             'name' => 'Global',
                             'plugin' => [
                                    'Sluggable' => [
                                        'lowercase' => false,
                                    ]
                             ]
                         ],
                     ]

Настройка старого плагина (на примере плагина Sanitizer)
```php
'controllerMap' => [
        'elfinder' => [
            'class' => 'mihaildev\elfinder\Controller',
            'connectOptions' => [
                'bind' => [
                    'upload.pre mkdir.pre mkfile.pre rename.pre archive.pre ls.pre' => array(
                        'Plugin.Sanitizer.cmdPreprocess'
                    ),
                    'ls' => array(
                        'Plugin.Sanitizer.cmdPostprocess'
                    ),
                    'upload.presave' => array(
                        'Plugin.Sanitizer.onUpLoadPreSave'
                    )
                ],
                'plugin' => [
                    'Sanitizer' => array(
                        'enable' => true,
                        'targets'  => array('\\','/',':','*','?','"','<','>','|'), // target chars
                        'replace'  => '_'    // replace to this
                    )
                ],
            ],


             'roots' => [
                             [
                                 'baseUrl'=>'@web',
                                 'basePath'=>'@webroot',
                                 'path' => 'files/global',
                                 'name' => 'Global',
                                 'plugin' => [
                                        'Sanitizer' => array(
                                                                'enable' => true,
                                                                'targets'  => array('\\','/',':','*','?','"','<','>','|'), // target chars
                                                                'replace'  => '_'    // replace to this
                                                            )
                                 ]
                             ],
                         ]

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

use mihaildev\elfinder\InputFile;
use mihaildev\elfinder\ElFinder;
use yii\web\JsExpression;

echo InputFile::widget([
    'language'   => 'ru',
    'controller' => 'elfinder', // вставляем название контроллера, по умолчанию равен elfinder
    'filter'     => 'image',    // фильтр файлов, можно задать массив фильтров https://github.com/Studio-42/elFinder/wiki/Client-configuration-options#wiki-onlyMimes
    'name'       => 'myinput',
    'value'      => '',
]);

echo $form->field($model, 'attribute')->widget(InputFile::className(), [
    'language'      => 'ru',
    'controller'    => 'elfinder', // вставляем название контроллера, по умолчанию равен elfinder
    'filter'        => 'image',    // фильтр файлов, можно задать массив фильтров https://github.com/Studio-42/elFinder/wiki/Client-configuration-options#wiki-onlyMimes
    'template'      => '<div class="input-group">{input}<span class="input-group-btn">{button}</span></div>',
    'options'       => ['class' => 'form-control'],
    'buttonOptions' => ['class' => 'btn btn-default'],
    'multiple'      => false       // возможность выбора нескольких файлов
]);

echo ElFinder::widget([
    'language'         => 'ru',
    'controller'       => 'elfinder', // вставляем название контроллера, по умолчанию равен elfinder
    'filter'           => 'image',    // фильтр файлов, можно задать массив фильтров https://github.com/Studio-42/elFinder/wiki/Client-configuration-options#wiki-onlyMimes
    'callbackFunction' => new JsExpression('function(file, id){}') // id - id виджета
]);

Использование при работе с PathController

use mihaildev\elfinder\InputFile;
use mihaildev\elfinder\ElFinder;
use yii\web\JsExpression;

echo InputFile::widget([
    'language'   => 'ru',
    'controller' => 'elfinder', // вставляем название контроллера, по умолчанию равен elfinder
    'path' => 'image', // будет открыта папка из настроек контроллера с добавлением указанной под деритории  
    'filter'     => 'image',    // фильтр файлов, можно задать массив фильтров https://github.com/Studio-42/elFinder/wiki/Client-configuration-options#wiki-onlyMimes
    'name'       => 'myinput',
    'value'      => '',
]);

echo $form->field($model, 'attribute')->widget(InputFile::className(), [
    'language'      => 'ru',
    'controller'    => 'elfinder', // вставляем название контроллера, по умолчанию равен elfinder
    'path' => 'image', // будет открыта папка из настроек контроллера с добавлением указанной под деритории 
    'filter'        => 'image',    // фильтр файлов, можно задать массив фильтров https://github.com/Studio-42/elFinder/wiki/Client-configuration-options#wiki-onlyMimes
    'template'      => '<div class="input-group">{input}<span class="input-group-btn">{button}</span></div>',
    'options'       => ['class' => 'form-control'],
    'buttonOptions' => ['class' => 'btn btn-default'],
    'multiple'      => false       // возможность выбора нескольких файлов
]);

echo ElFinder::widget([
    'language'         => 'ru',
    'controller'       => 'elfinder', // вставляем название контроллера, по умолчанию равен elfinder
    'path' => 'image', // будет открыта папка из настроек контроллера с добавлением указанной под деритории 
    'filter'           => 'image',    // фильтр файлов, можно задать массив фильтров https://github.com/Studio-42/elFinder/wiki/Client-configuration-options#wiki-onlyMimes
    'callbackFunction' => new JsExpression('function(file, id){}') // id - id виджета
]);

CKEditor

use mihaildev\elfinder\ElFinder;

$ckeditorOptions = ElFinder::ckeditorOptions($controller,[/* Some CKEditor Options */]);

Для указания подкаталога (при использовании PathController) `php use mihaildev\elfinder\ElFinder;

$ckeditorOptions = ElFinder::ckeditorOptions([$controller, 'path' => 'some/sub/path'],[/* Some CKEditor Options */]);


Использование совместно с приложением "mihaildev/yii2-ckeditor" (https://github.com/MihailDev/yii2-ckeditor)

```php
use mihaildev\ckeditor\CKEditor;
use mihaildev\elfinder\ElFinder;

$form->field($model, 'attribute')->widget(CKEditor::className(), [
  ...
  'editorOptions' => ElFinder::ckeditorOptions('elfinder',[/* Some CKEditor Options */]),
  ...
]);

Для указания подкаталога (при использовании PathController)

use mihaildev\ckeditor\CKEditor;
use mihaildev\elfinder\ElFinder;

$form->field($model, 'attribute')->widget(CKEditor::className(), [
  ...
  'editorOptions' => ElFinder::ckeditorOptions(['elfinder', 'path' => 'some/sub/path'],[/* Some CKEditor Options */]),
  ...
]);

Проблемы

При встраивание без iframe возможен конфликт с bootstrap.js. Studio-42/elFinder#740 Решение - добавляем в шаблон запись `php

mihaildev\elfinder\Assets::noConflict($this);


## Полезные ссылки

ElFinder Wiki - https://github.com/Studio-42/elFinder/wiki

Flysystem

https://github.com/MihailDev/yii2-elfinder-flysystem/

https://github.com/barryvdh/elfinder-flysystem-driver

https://github.com/creocoder/yii2-flysystem

http://flysystem.thephpleague.com/





]]>
0
[extension] ianikanov/yii2-wce Sun, 24 Mar 2019 21:22:14 +0000 https://www.yiiframework.com/extension/ianikanov/yii2-wce https://www.yiiframework.com/extension/ianikanov/yii2-wce ianikanov ianikanov

Widget as Controller Yii2 Extension

  1. Installation
  2. Usage

Ability to generate widgets with interface similar to controller with basic CRUD actions for specific model

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist ianikanov/yii2-wce "dev-master"

or add

"ianikanov/yii2-wce": "dev-master"

to the require section of your composer.json file.

Usage

Once the extension is installed, add new template to your config file : `php if (YII_ENV_DEV) {

$config['modules']['gii'] = [
    'class' => 'yii\gii\Module',      
    'allowedIPs' => ['127.0.0.1', '::1', '192.168.0.*', '192.168.178.20'],  
    'generators' => [ //here
        'widgetCrud' => [
            'class' => '\ianikanov\wce\templates\crud\Generator',
            'templates' => [
                'WCE' => '@vendor/ianikanov/yii2-wce/templates/crud/default', // template name
            ],
        ],
    ],
];

} And register embedded controller:php $config = [

...
'controllerMap' => [
    'wce-embed' => '\ianikanov\wce\Controller',
],
...

]; ` Then run gii, select "CRUD Controller Widget" fill the form and generate the code.

To use widget in any other form follow examples below.

To show list of items, for example, the list of Posts related to the current model: `php <?= app\widgets\PostControllerWidget::widget([

'action' => 'index',
'params' => [
    'query' => $model->getPosts(),
],

]) ?> `

To show a single item details, for example the post `php <?= app\widgets\PostControllerWidget::widget([

'action' => 'view',
'params' => [
    'id' => $post_id,
],

]) ?> `

To show create button with modal window: `php <?= app\widgets\PostControllerWidget::widget(['action' => 'create']) ?> `

To show update button with modal window: `php <?= app\widgets\PostControllerWidget::widget(['action' => 'update', 'params'=>['id' => $model->id]]) ?> `

To show delete button: `php <?= app\widgets\PostControllerWidget::widget(['action' => 'delete', 'params'=>['id' => $model->id]]) ?> `

]]>
0
[news] Yii 2.0.17 Fri, 22 Mar 2019 21:51:24 +0000 https://www.yiiframework.com/news/203/yii-2-0-17 https://www.yiiframework.com/news/203/yii-2-0-17 samdark samdark

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

Version 2.0.17 is a minor release of Yii 2.0 which contains some bugfixes including a security fix.

No known changes that could affect existing applications were made.

Both basic and advanced applications got fixes for recent Codeception, got updated debug and gii versions to version 2.1.0. Basic application now uses swiftmailer 2.1.0.

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.

Below we summarize some of the enhancements and changes that slipped into this release. A complete list of changes can be found in the CHANGELOG.

]]>
0
[extension] diazoxide/yii2-blog Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/diazoxide/yii2-blog https://www.yiiframework.com/extension/diazoxide/yii2-blog diazoxide diazoxide

diazoxide/yii2-blog

Advanced Yii2 Blog module. Posts, Categories, Comments, Tags, With Slider Revolution, SEO tags, Social Tags
Features
  • Blog Posts
    • Title
    • Slug
    • Multiple Categories for each post
    • Brief
    • Content
      • Custom Redactor/wysiwyg editor
    • Books
      • Chapters and sub Chapters
      • Nested structure
      • Nested breadcrumbs
      • BBCode support
      • Custom BBCode styling
  • Blog Categories
  • Blog Tags
  • Blog Comments
  • Custom Widgets
    • Dynamic widgets
    • Custom backend panel
    • Custom Styling
    • Custom Javascript
    • Infinite Scroll for each widgted
    • Category integration
  • Slider Revolution

installation

add to composer.json

{
    "require": {
      "diazoxide/yii2-blog": "dev-master"
    }
}

common configuration

 'modules'=>[
     'blog' => [
         'class' => "diazoxide\blog\Module",
         'urlManager' => 'urlManager',
         'imgFilePath' => dirname(__DIR__) . '/public/uploads/img/blog/',
         'imgFileUrl' => '/uploads/img/blog/',
         // You can change any view file for each route
         'frontendViewsMap'=>[
             'blog/default/index'=>'@app/views/blog/index'
         ],
         // You can change any layout for each route
         'frontendLayoutMap'=>[
             'blog/default/view'=>'@app/views/layouts/main-with-two-sidebar',
             'blog/default/archive'=>'@app/views/layouts/main-with-right-sidebar',
         ],
         'homeTitle'=>'Blog title',
         'userModel' => "\app\models\User",
         'userPK' => 'id',
         'userName' => 'username',
         'showClicksInPost'=>false,
         'enableShareButtons' => true,
         'blogPostPageCount' => '10',
         'schemaOrg' => [
             'publisher' => [
                 'logo' => '/path/to/logo.png',
                 'logoWidth' => 200,
                 'logoHeight' => 47,
                 'name' => "Blog title",
                 'phone' => '+1 800 488 80 85',
                 'address' => 'Address 13/5'
             ]
         ]
     ],
 ]

backend configuration

$config['modules']['blog']['controllerNamespace'] = 'diazoxide\blog\controllers\backend';

Migration

after install run migration command

php yii migrate --migrationPath=@vendor/diazoxide/yii2-blog/migrations

Custom urlManager rules for beautiful links

archive url in frontend

https://blog.com/archive

category url in frontend

https://blog.com/category/politics

post url in frontend like a wordpress and seo friendly

https://blog.com/2019/11/21/your-post-slug

 'urlManager' => [
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'rules' => [
        //F.E. https://blog.com/category/politics
        '/category/<slug>' => '/blog/default/archive',
        
        //F.E. https://blog.com/archive
        '/archive' => '/blog/default/archive',
        
        //F.E. https://blog.com/2019/11/21/your-post-slug
        [
            'pattern' => '<year:\d{4}>/<month:\d{2}>/<day:\d{2}>/<slug>',
            'route' => '/blog/default/view',
            'suffix' => '/'
        ],
    ],
],
]]>
0
[news] Queue extension 2.2.0 released Tue, 19 Mar 2019 22:45:53 +0000 https://www.yiiframework.com/news/202/queue-extension-2-2-0-released https://www.yiiframework.com/news/202/queue-extension-2-2-0-released samdark samdark

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

The release is fixing important bugs, reduces roundtrips to beanstalk server when removing a job, marking ErrorEvent as deprecated and making job execution result being forwarded to event handler.

Full changelog is available at GitHub.

]]>
0
[extension] luyadev/luya-headless Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/luyadev/luya-headless https://www.yiiframework.com/extension/luyadev/luya-headless nadario nadario

LUYA Logo

LUYA Headless Client

  1. Installation
  2. Intro
  3. Documentation
  4. Development and Contribution

A client library to access content from the LUYA APIs (or any other REST API).

LUYA Build Status Latest Stable Version Maintainability Test Coverage Total Downloads Slack Support

Compared to the other LUYA packages, this package adheres to Semantic Versioning!

Installation

Add the LUYA headless client library to your composer.json:

composer require luyadev/luya-headless

Intro

Quick intro about how to use the headless library with a custom Endpoint: Create the Api Class (this very similar to Active Record pattern):

class ApiCars extends \luya\headless\ActiveEdnpoint
{
    public $id;
    public $name;
    public $year;

    public function getEndpointName()
    {
        return '{{api-cars}}';
    }
}

With the new ApiCars class you can now insert, update or fetch data:

use luya\headless\Client;

// build client object with token and server infos
$client = new Client('API_TOKEN', 'http://localhost/luya-kickstarter/public_html');

// create new value
$car = new ApiCars();
$car->name = 'BMW';
$car->year = 2019;
$car->save($client);

// find a given user by its ID
$car = ApiCars::findOne(1, $client);
echo $car->name; // BMW
echo $car->year; // 2019

// update an existing value
$car->year = '2018';
$car->save($client);

// iterate all cars
$users = ApiCars::find()->setSort(['id' => SORT_ASC])->all($client);
foreach ($users->getModels() as $car) {
      echo $car->name;
}

Documentation

See the full Documentation in order to see how to make put, delete or post request, handle pagination or access the cms blocks.

Development and Contribution

]]>
0
[extension] thtmorais/yii2-pace Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/thtmorais/yii2-pace https://www.yiiframework.com/extension/thtmorais/yii2-pace thtmorais thtmorais

PACE (Progress Automatically Certain to Entertain) for Yii PHP Framework

  1. Installation
  2. Usage
  3. Configuration

PACE (Progress Automatically Certain to Entertain) - Automatic page load progress bar for Yii PHP Framework

Installation

The preferred way to install this extension is through composer.

Either run

composer require thtmorais/yii2-pace "*"

or add

"thtmorais/yii2-pace": "*"

to the require section of your composer.json file.

Usage

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

<?php

use thtmorais\pace\Pace;

echo Pace::widget();

?>

or

<?= \thtmorais\pace\Pace::widget() ?>

We recommend using in the layouts/main.php file. Or if you prefer in each view file with their respective settings.

Configuration

By default the PACE comes configured with blue color and animation minimal.

You can add general rule for all views in the config/params.php file as follows:

<?php
    return [
        'paceOptions' => [
            'color' =>  'blue',
            'theme' => 'minimal',
            'options' => []
        ]
    ];
?>

or individually in each view:

<?php
   
use thtmorais\pace\Pace;

echo Pace::widget([
    'color'=>'red',
    'theme'=>'corner-indicator',
    'options'=>[]
]);

?>

You can preview themes and colors here.

]]>
0
[wiki] Nested Set with Yii2 Mon, 18 Mar 2019 12:47:32 +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>
]]>
0
[news] Gii extension 2.1.0 released Sun, 17 Mar 2019 19:29:45 +0000 https://www.yiiframework.com/news/201/gii-extension-2-1-0-released https://www.yiiframework.com/news/201/gii-extension-2-1-0-released samdark samdark

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

Additionally to bugfixes, there are some enhancements in this release:

  1. New version has less dependencies thanks to simialbi. It doesn't depend on bootstrap package anymore.
  2. New option added to singularize class names in modele generator.

See the CHANGELOG for details.

]]>
0
[news] Debug extension 2.1.0 released Sun, 17 Mar 2019 19:18:56 +0000 https://www.yiiframework.com/news/200/debug-extension-2-1-0-released https://www.yiiframework.com/news/200/debug-extension-2-1-0-released samdark samdark

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

Additionally to bugfixes, there some enhancements:

  1. Module has checkAccessCallback property that you can set to a callable that returns a boolean determining if current user should be allowed to access debug.
  2. New "dump" panel was added. It collects and displays debug messages logged with Logger::LEVEL_TRACE.
  3. New version has less dependencies thanks to simialbi. It doesn't depend on bootstrap package anymore.
  4. There are small visual adjustments as well.

See the CHANGELOG for details.

]]>
0
[news] Bootstrap 4 extension version 2.0.1 released Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/news/199/bootstrap-4-extension-version-2-0-1-released https://www.yiiframework.com/news/199/bootstrap-4-extension-version-2-0-1-released samdark samdark

We are very pleased to announce the release of Bootstrap 4 extension version 2.0.1. There are five bugs fixed found since initial release.

]]>
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
[extension] tonisormisson/yii2-address-form Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/tonisormisson/yii2-address-form https://www.yiiframework.com/extension/tonisormisson/yii2-address-form t6nnp6nn t6nnp6nn

Yii2 Address-form module

  1. powered by rinvex/country
  2. Example

Scrutinizer Code Quality Build Status Code Coverage

A module doing address-form fields with dependent pre-set country-region drop-downs. Countries & regions powered by:

powered by rinvex/country

250 countries & regions worldwide available

Example

add module config

the module part will take care of dep-drop ajax queries


    'modules' => [
        //...
        'addressform' =>[
            'class' => \tonisormisson\addressform\Module::class,
        ],
        //...
    ]
place the widet
use tonisormisson\addressform\AddressForm; 

echo AddressForm::widget([
    'allowedCountries' => ["EE", "LV", "LT"],
    'placeHolders' = [
        // custom placeholders here if needed
        'country' => ,
        'state' => ,
        'city' => ,
        'postCode' => ,
        'addressLine1' => ,
        'addressLine2' => ,
    ],
            
]);
and catch the address in controller
use tonisormisson\addressform\models\Address;
$address = new Address();
$address->load(Yii::$app->request->post());

// load the address to your models
// eg :
$model->address_data = Json::encode($address);

]]>
0
[extension] andmemasin/yii2-emails-validator Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/andmemasin/yii2-emails-validator https://www.yiiframework.com/extension/andmemasin/yii2-emails-validator t6nnp6nn t6nnp6nn

yii2-emails-validator

A Yii2 module to do bulk e-mails validation

Scrutinizer Code Quality Build Status codecov

live demo:

]]>
0
[extension] andmemasin/actionlog Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/andmemasin/actionlog https://www.yiiframework.com/extension/andmemasin/actionlog t6nnp6nn t6nnp6nn ]]> 0 [extension] codemonauts/yii2-cloudwatch-logs Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/codemonauts/yii2-cloudwatch-logs https://www.yiiframework.com/extension/codemonauts/yii2-cloudwatch-logs codemonauts codemonauts

Yii2 Cloudwatch Logs Target

  1. Installation and Configuration
  2. Configuration Options
  3. Cloudwatch Logs Insights

A Yii2 log target for AWS Cloudwatch Logs.

Installation and Configuration

Install the package through composer:

composer require codemonauts/yii2-cloudwatch-logs

And then add this to your application configuration:

<?php
return [
    // ...
    'components' => [
        // ...
        'log' => [
            'targets' => [
                [
                    'class' => \codemonauts\cloudwatchlogs\Target::class,
                    'region' => 'eu-west-1',
                    'logGroup' => '/webserver/production/my-craft',
                    'logStream' => 'instance-1', // omit for automatic instance ID
                    'levels' => ['error', 'warning', 'info', 'trace', 'profile'],
                    'logVars' => ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER'],
                    'key' => 'your-key', // omit for instance role
                    'secret' => 'your-secret', // omit for instance role
                ],
                // ...
            ],
        ],

Configuration Options

  • (string) $region (required) The name of the AWS region e.g. eu-west-1
  • (string) $logGroup (required) The name of the log group.
  • (string) $logStream (optional) The name of the log stream. If omitted, it will try to determine the ID of the EC2 instance running on.
  • (array) $levels (optional) Log level. Default by Yii2: ['error', 'warning', 'info', 'trace', 'profile']
  • (array) $logVars (optional) Variables to log. Default by Yii2: ['_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER']
  • (string) $key (optional) Your AWS access key.
  • (string) $secret (optional) Your AWS secret.

Cloudwatch Logs Insights

If you want to parse the logs with Insights, then do something like this:

fields @timestamp, @message
| sort @timestamp desc
| limit 20
| parse '[*][*][*][*][*] *' as ip, userId, sessionId, logLevel, category, message
]]>
0
[extension] zhuravljov/yii2-queue-monitor Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/zhuravljov/yii2-queue-monitor https://www.yiiframework.com/extension/zhuravljov/yii2-queue-monitor KiTE KiTE

Yii2 Queue Analytics Module

  1. Installation
  2. Usage

The module collects statistics about working of queues of an application, and provides web interface for research. Also the module allows to stop and replay any jobs manually.

Latest Stable Version Total Downloads Scrutinizer Code Quality

Installation

The preferred way to install the extension is through composer. Add to the require section of your composer.json file:

"zhuravljov/yii2-queue-monitor": "~0.1"

Usage

To configure the statistics collector, you need to add monitor behavior for each queue component. Update common config file:

return [
    'components' => [
        'queue' => [
            // ...
            'as jobMonitor' => \zhuravljov\yii\queue\monitor\JobMonitor::class,
            'as workerMonitor' => \zhuravljov\yii\queue\monitor\WorkerMonitor::class,
        ],
    ],
];

There are storage options that you can configure by common config file:

return [
    'container' => [
        'singletons' => [
            \zhuravljov\yii\queue\monitor\Env::class => [
                'cache' => 'cache',
                'db' => 'db',
                'pushTableName'   => '{{%queue_push}}',
                'execTableName'   => '{{%queue_exec}}',
                'workerTableName' => '{{%queue_worker}}',
            ],
        ],
    ],
];

If you want use migrations of the extension, configure migration command in console config:

'controllerMap' => [
    'migrate' => [
        'class' => \yii\console\controllers\MigrateController::class,
        'migrationNamespaces' => [
            //...
            'zhuravljov\yii\queue\monitor\migrations',
        ],
    ],
],

And apply migrations.

Finally, modify your web config file to turn on web interface:

return [
    'bootstrap' => [
        'monitor',
    ],
    'modules' => [
        'monitor' => [
            'class' => \zhuravljov\yii\queue\monitor\Module::class,
        ],
    ],
];

It will be available by URL http://yourhost.com/monitor.

]]>
0
[news] Yii release cycle clarified Tue, 05 Mar 2019 08:17:06 +0000 https://www.yiiframework.com/news/198/yii-release-cycle-clarified https://www.yiiframework.com/news/198/yii-release-cycle-clarified samdark samdark

We have added a new page to yiiframework.com website called "release cycle". Its purpose is to clarify about how long a certain framework version will be supported.

Default policy is that after current major version release previous major version has:

  • Two years of bug fixes.
  • Three years of security and PHP compatibility fixes.

For example, in case Yii 3.0 would be released today, 2.0 would receive bugfixes till March 2021 and security fixes till March 2024.

]]>
0
[extension] immusen/yii2-swoole-websocket Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/immusen/yii2-swoole-websocket https://www.yiiframework.com/extension/immusen/yii2-swoole-websocket immusen immusen

Websocket rpc server For Yii2 Base On Swoole 4

  1. Installation
  2. Test or Usage
  3. Example:
  4. Coding:

Websocket server for Yii2 base on swoole 4, Support JSON-RPC, Resolve 'method' as a route reflect into controller/action, And support http or redis pub/sub to trigger async task from your web application.

Installation

Install Yii2: Yii2.

Install swoole: swoole, recommend version 4+.

Other dependency: php-redis extension.

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist immusen/yii2-swoole-websocket "~1.0"

or add

"immusen/yii2-swoole-websocket": "~1.0"

to the require section of your composer.json file.

Test or Usage

after installation, cd project root path, e.g. cd yii2-advanced-project/ mv vendor/immusen/yii2-swoole-websocket/example/websocket ./ mv vendor/immusen/yii2-swoole-websocket/example/websocket-server ./ chmod a+x ./websocket-server run: ./websocket-server config : ` vim ./websocket/config/params.php <?php return [

'listen' => 8721,
'daemonize' => 0,

]; ` or coding in ./websocket/controllers/

Example:

Chat room demo, code: ./example/websocket/controllers/RoomController.php

client join room: websocket client send:

`

{
    "jsonrpc":"2.0",
    "id":1,
    "method":"room/join",
    "params":{
        "id":"100111",
        "info":{
            "age":"19",
            "gender":"f"
        }
    }
}

> the websocket client which had joined same room (id:100111) will get message like this:

{
    "jsonrpc":"2.0",
    "id":1,
    "result":{
        "type":"join",
        "count":85,
        "info":{
            "age":"19",
            "gender":"f"
        }
    }
}

`

chat message websocket client send: `

{
    "jsonrpc":"2.0",
    "id":1,
    "method":"room/msg",
    "params":{
        "id":"100111",
        "content":{
            "text":"Hello world!"
        }
    }
}
this room member will get:
{
    "jsonrpc":"2.0",
    "id":1,
    "result":{
        "text":"Hello world!"
    }
}

Coding:

1, Create Controller under websocket/controllers, or other path which defined with "controllerNamespace" in websocket/config/main.php ` <?php namespace websocket\controllers;

use immusen\websocket\src\Controller;

class FooController extends Controller {

 public function actionBar($param_1, $param_2 = 0, $param_n = null)
 {
      # add current fd into a group/set, make $param_1 or anyother string as the group/set key
      $this->joinGroup($this->fd, $param_1);
      
      # reply message to current client by websocket
      $this->publish($this->fd, ['p1' => $param_1, 'p2' => $param_2]);
      
      # get all fds stored in the group/set
      $fds_array = $this->groupMembers($param_1);
      
      # reply message to a group
      $this->publish($fds_array, ['p1' => $param_1, 'p2' => $param_2]);
      #or
      $this->sendToGroup(['p1' => $param_1, 'p2' => $param_2], $param_1);
      
      # operate redis via redis pool
      $this->redis->set($param_1, 0)
 }

 //...

} `

2, Send JSON-RPC to trigger that action `

{
    "jsonrpc":"2.0",
    "id":1,
    "method":"foo/bar",
    "params":{
        "param_1":"client_01",
        "param_2":100,
        "param_n":{
            "time":1551408888,
            "type":"report"
        }
    }
}

---

All of client to server rpc command also can send by HTTP or Redis publish, This feature will helpful for some async task triggered from web application. Example in chat room case: 

HTTP request: 

http://127.0.0.1:8721/rpc?p={"jsonrpc":"2.0","id":1,"method":"room/msg","params":{"id":"100111","content":{"text":"System warning!"}}} OR redis-cli: 127.0.0.1:6379> publish rpc '{"jsonrpc":"2.0","id":1,"method":"room/msg","params":{"id":"100111","content":{"text":"System warning!"}}}' OR in Yii web application Yii:$app->redis->publish('rpc', '{"jsonrpc":"2.0","id":1,"method":"room/msg","params":{"id":"100111","content":{"text":"System warning!"}}}') OR use Hook (recommend), Support 'runOnce' to keep method run only once even if multiple swoole instances online, @see [immusen/yii2-swoole-websocket/Hook.php](https://github.com/immusen/yii2-swoole-websocket/blob/master/Hook.php) Yii::$app->hook->run('room/msg', ['id' => 100111, 'content' => ['text' => 'System warning!']]); `

]]>
0
[extension] immusen/yii2-swoole-mqtt Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/immusen/yii2-swoole-mqtt https://www.yiiframework.com/extension/immusen/yii2-swoole-mqtt immusen immusen

MQTT For Yii2 Base On Swoole 4

  1. Installation
  2. Test or Usage
  3. Example:
  4. Coding:

MQTT server for Yii2 base on swoole 4, Resolve topic as a route reflect into controller/action/param, And support redis pub/sub to trigger async task from your web application

Installation

Install Yii2: Yii2.

Install swoole: swoole, recommend version 4+.

Other dependency: php-redis extension.

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist immusen/yii2-swoole-mqtt "~1.0"

or add

"immusen/yii2-swoole-mqtt": "~1.0"

to the require section of your composer.json file.

Test or Usage

# after installation, cd project root path, e.g. cd yii2-advanced-project/
mv vendor/immusen/yii2-swoole-mqtt/example/mqtt ./
mv vendor/immusen/yii2-swoole-mqtt/example/mqtt-server ./
chmod a+x ./mqtt-server
# run:
./mqtt-server
# config :
cat ./mqtt/config/params.php
<?php
return [
    'listen' => 8721,
    'daemonize' => 0,
    'auth' => 1, // config auth class in ./main.php
];
# or coding in ./mqtt/controllers/

Test client: MQTTLens, MQTT.fx

Example:

Case A: Subscribe/Publish

1, mqtt client subscribe topic: room/count/100011

2.1, mqtt client publish: every time publish topic: room/join/100011, the subscribe side will get count+1, or publish topic: room/leave/100011 get count -1.

2.2, redis client pulish: every time $redis->publish('async', 'room/join/100011'), the subscribe side will get count+1, or $redis->publish('async', 'room/leave/100011') get count -1.

Case B: Publish(Notification Or Report)

mqtt client publish topic: report/coord/100111 and payload: e.g. 110.12345678,30.12345678,0,85

Coding:

MQTT subscribe topic: "channel/count/100001" will handle at: `

class ChannelController{
    public function actionCount($channel_id){
        echo "client {$this->fd} subscribed the count change of channel {$channel_id}";
    }
}
> //client 1 subscribed the count change of channel 100001


MQTT Publish Topic:  "channel/join/100001"  with payload: "Foo"  will handle at:
class ChannelController{
    public function actionJoin($channel_id, $who){
        echo "{$who} join in channel {$channel_id}";
        #then broadcast update to all client who subscribed channel 100001
        #$this->publish($fds, $sub_topic, $count);
    }
}
> // Foo join in channel 100001

MQTT
----

About MQTT: [MQTT Version 3.1.1 Plus Errata 01](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html)

> Non-complete implementation of MQTT 3.1.1 in this project, Upgrading...

]]>
0
[news] Yii 2.0.16.1 is released Thu, 28 Feb 2019 07:57:48 +0000 https://www.yiiframework.com/news/197/yii-2-0-16-1-is-released https://www.yiiframework.com/news/197/yii-2-0-16-1-is-released samdark samdark

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

Version 2.0.16.1 is a bugfix release of Yii 2.0 which fixed regressions in 2.0.16.

]]>
0
[extension] pcrt/yii2-datepicker Wed, 27 Feb 2019 21:33:29 +0000 https://www.yiiframework.com/extension/pcrt/yii2-datepicker https://www.yiiframework.com/extension/pcrt/yii2-datepicker Pcrt Pcrt

Yii2-Datepicker

  1. Installation
  2. Usage
  3. License

Daterangepicker gives you a customizable daterangepicker with support for multidate, time, localization and many other highly used options.

Installation

The preferred way to install this extension is through composer.

Either run

$ php composer.phar require pcrt/yii2-datepicker "*"

or add

"pcrt/yii2-datepicker": "*"

to the require section of your composer.json file.

Usage

Once the extension is installed, modify your application configuration to include:

use pcrt\widgets\datepicker\Datepicker:


// with \yii\bootstrap\ActiveForm;
echo $form
    ->field($model, 'attribute')
    ->widget(
        Datepicker::class,
        [
          'clientOptions' => [
            'singleDatePicker' => true,
            'showDropdowns' => true,
          ]
        ]
    );

// as widget
echo Datepicker::widget([
    'clientOptions' => [
      'showDropdowns' => true,
    ]
]);

License

Yii2-Datepicker is released under the BSD-3 License. See the bundled LICENSE.md for details.

Enjoy!

]]>
0
[extension] pcrt/yii2-ajax-pager Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/pcrt/yii2-ajax-pager https://www.yiiframework.com/extension/pcrt/yii2-ajax-pager Pcrt Pcrt

Yii2-Ajax-Pager

  1. Installation
  2. Usage
  3. License

Yii2 Component extend yii\widgets\ContentDecorator url used to add ajax-pagination functionality to GridView and ListView base component .

This extension create a Wrapper around content and permit to chose between "Paginator Pattern" or "InfiniteScroll Pattern" to manage pagination functionality without reload page .

Installation

The preferred way to install this extension is through composer.

Either run

$ php composer.phar require pcrt/yii2-ajax-pager "@dev"

or add

"pcrt/yii2-ajax-pager": "@dev"

to the require section of your composer.json file.

Usage

Once the extension is installed, you can add component in your View: The component can work as Pagination :

use pcrt/Paginator;
....

<?php Paginator::begin([
    'type' => 'Pagination',
    'id' => 'pcrt-pagination', // Id of pagination container
    'id_wrapper' => 'pcrt-pagination-wrapper', // Id of wrapper container
    'view' => $this,
]) ?>

$this->renderPartial('ajax/list', [ 'dt' => $dataProvider ]);
// or do your magic here !

<?php Paginator::end() ?>

or in InfiniteScroll mode:

use pcrt/Paginator;
....

<?php Paginator::begin([
    'type' => 'InfiniteScroll',
    'append' => '.pcrt-card', // Selector for pagination element extractor
    'id_wrapper' => 'pcrt-pagination-wrapper', // Id of wrapper container
    'view' => $this,
]) ?>

$this->renderPartial('ajax/_card', [ 'dt' => $dataProvider ]);
// or do your magic here !

<?php Paginator::end() ?>

You can also pass an alternative "wapper view" file :

use pcrt/Paginator;
....

<?php Paginator::begin([
    'type' => 'InfiniteScroll',
    'viewFile' => '@app/views/wrapper.php', // Alternative view Wrapper
    'append' => '.pcrt-card', // Selector for pagination element extractor
    'id_wrapper' => 'pcrt-pagination-wrapper', // Id of wrapper container
    'view' => $this,
]) ?>

// Remenber to return $content variable inside of wrapper;

In the controller for InfiniteScroll return a renderAjax file:

class MyController extends Controller {

  public function actionGetGridView(){

    public function actionGetGridView($pageNumber=0,$pageSize=50){
      if($pageSize == ""){
        $pageSize = 50;
      }
      $request = \Yii::$app->request;

      $searchModel = new MyControllerSearch();
      $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
      $dataProvider->pagination = [
              'pageSize'=>$pageSize,
              'page'=>$pageNumber-1,
      ];
      $result = $dataProvider->getTotalCount();
      $data = $this->renderAjax('_list', [
          'searchModel' => $searchModel,
          'dataProvider' => $dataProvider,
      ]);
      return $data;

  	}
	}

}

for Pagination return a jSON Object with data (html render) and total (total number of element):

class MyController extends Controller {

  public function actionGetGridView($pageNumber=0,$pageSize=50){
    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    if($pageSize == ""){
      $pageSize = 50;
    }
    $request = \Yii::$app->request;

    $searchModel = new MyControllerSearch();
    $dataProvider = $searchModel->search();
    $dataProvider->pagination = [
            'pageSize'=>$pageSize,
            'page'=>$pageNumber-1,
    ];
    $result = $dataProvider->getTotalCount();
    $data = $this->renderAjax('_list', [
        'searchModel' => $searchModel,
        'dataProvider' => $dataProvider,
    ]);
    return ['html'=>$data,'total'=>$result];
	}
}

License

Yii2-Ajax-Pager is released under the BSD-3 License. See the bundled LICENSE.md for details.

Useful URLs

  1. Installation
  2. Usage
  3. License

Enjoy!

]]>
0
[extension] pcrt/yii2-gii Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/pcrt/yii2-gii https://www.yiiframework.com/extension/pcrt/yii2-gii Pcrt Pcrt

Yii2-gii

  1. Installation
  2. Usage
  3. License

Additional Gii code generator .

This extension add code generator to Yii2 framework Gii extension.

Installation

The preferred way to install this extension is through composer.

Either run

$ php composer.phar require pcrt/yii2-gii "*"

or add

"pcrt/yii2-gii": "*"

to the require section of your composer.json file.

Usage

Once the extension is installed, modify your application configuration to include:



  $config['modules']['gii'] = [
      'class' => 'yii\gii\Module',
      ....
      'generators' => [ // HERE
          'pcrtmodel' => [
              'class' => 'pcrt\generators\model\Generator',
              'templates' => [
                  'pcrt' => '@vendor/pcrt/yii2-gii/generators/model/pcrt',
              ]
          ],
          'pcrtcrud' => [
              'class' => 'pcrt\generators\crud\Generator',
              'templates' => [
                  'pcrt' => '@vendor/pcrt/yii2-gii/generators/crud/pcrt',
              ]
          ]
      ],
      ....
      // uncomment the following to add your IP if you are not connecting from localhost.
      // 'allowedIPs' => ['127.0.0.1', '::1'],
  ];

License

Yii2-gii is released under the BSD-3 License. See the bundled LICENSE.md for details.

Enjoy!

]]>
0
[extension] pcrt/yii2-latex Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/pcrt/yii2-latex https://www.yiiframework.com/extension/pcrt/yii2-latex Pcrt Pcrt

Yii2-Latex

  1. Installation
  2. Usage
  3. License

Latex2PDF formatter for Yii2 .

This extension "format" Latex responses to PDF files (by default Yii2 includes HTML, JSON and XML formatters). Great for reports in PDF format using Latex views/layouts.

Installation

The preferred way to install this extension is through composer.

Either run

$ php composer.phar require pcrt/yii2-latex "*"

or add

"pcrt/yii2-pdf": "*"

to the require section of your composer.json file.

Usage

Once the extension is installed, modify your application configuration to include:

return [
	'components' => [
		...
		'response' => [
			'formatters' => [
				'pdf' => [
					'class' => 'pcrt\latex\Latex2PdfResponseFormatter',
					'latexbin' => '/usr/local/bin/pdflatex',
					'buildpath' => '/folder/you/prefer' // for default use current folder
					'keepfile' => false // if true not clean debug file ( debug purpose only )
 				],
			]
		],
		...
	],
];

For default the buildpath variable is set on your @webroot folder .

In the controller:


class MyController extends Controller {
	public function actionPdf(){
		Yii::$app->response->format = 'latex';
		$this->layout = '//print'; // A siple template without any html code
		return $this->render('myview', []);
	}
}

License

Yii2-Latex is released under the BSD-3 License. See the bundled LICENSE.md for details.

Useful URLs

  1. Installation
  2. Usage
  3. License

Enjoy!

]]>
0
[extension] pcrt/yii2-select2 Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/pcrt/yii2-select2 https://www.yiiframework.com/extension/pcrt/yii2-select2 Pcrt Pcrt

Yii2-select2

  1. Installation
  2. Usage
  3. License

Select2 gives you a customizable select box with support for searching, tagging, remote data sets, infinite scrolling, and many other highly used options.

Installation

The preferred way to install this extension is through composer.

Either run

$ php composer.phar require pcrt/yii2-select "*"

or add

"pcrt/yii2-select2": "*"

to the require section of your composer.json file.

Usage

Once the extension is installed, modify your application configuration to include:

use pcrt\widgets\select2\Select2:


// with \yii\bootstrap\ActiveForm;
echo $form
    ->field($model, 'attribute')
    ->widget(
        Select2::class, 
        [
            'items' => $data, // $data should be the same as the items provided to a regular yii2 dropdownlist
        ]
    );

// as widget
echo Select2::widget([
    'name' => 'my-name',
    'value' => 'my-value',
    'clientOptions' => [
        'maximumInputLength' => 20
    ]
]);

License

Yii2-select2 is released under the BSD-3 License. See the bundled LICENSE.md for details.

Enjoy!

]]>
0
[extension] rakhmatov/yii2-payment Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/rakhmatov/yii2-payment https://www.yiiframework.com/extension/rakhmatov/yii2-payment rakhmatov rakhmatov ]]> 0 [extension] enchikiben/yii2-sitemap Tue, 26 Mar 2019 02:03:36 +0000 https://www.yiiframework.com/extension/enchikiben/yii2-sitemap https://www.yiiframework.com/extension/enchikiben/yii2-sitemap enchikiben enchikiben

yii2-sitemap

  1. Installation
  2. Configure
  3. Use

Installation

The preferred way to install this extension is through composer.

php composer.phar require --prefer-dist "enchikiben/yii2-sitemap" "*"

or

"enchikiben/yii2-sitemap" : "*"

Configure

'modules' => [
    'sitemap' => [
        'class' => 'enchikiben\sitemap\Sitemap',
        'controllerDirAlias' => '@frontend/controllers'
    ],
],

Add a new rule for urlManager of your application's configuration file, for example:

'urlManager' => [
    'rules' => [
        ['pattern' => 'sitemap', 'route' => 'sitemap/default/index', 'suffix' => '.xml'],
    ],
],

Use

class SiteController extends Base
{

    /**
     * @sitemap priority=1
     */
    public function actionIndex()
    {
    } 

    /**
     * @sitemap priority=0.8
     */
    public function actionConfidentiality()
    {
    }
}

or

class NewsController extends Base
{
    /**
     * @sitemap priority=0.5 changefreq=monthly route=['/news/view','id'=>$model->id] model=common\models\News condition=['status'=>1]
     */
    public function actionView($id)
    {
        
    }
}
]]>
0
[news] Yii 2.0.16 is released Thu, 28 Feb 2019 07:29:20 +0000 https://www.yiiframework.com/news/196/yii-2-0-16-is-released https://www.yiiframework.com/news/196/yii-2-0-16-is-released CeBe CeBe
  1. Active Record
  2. Migrations
  3. Databases
  4. Helpers
  5. GridView
  6. jQuery
  7. Mutex
  8. Security fixes
  9. Project templates
  10. A bit about Yii 3.0

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

Version 2.0.16 is a minor release of Yii 2.0 which contains more than a hundred enhancements and bug fixes including security fixes.

Yii 2.0 reached feature freeze more than a year ago, meaning that the 2.0 branch will only receive bug fixes. That was done in order to allow the Yii Team to focus on the upcoming Yii 3 rewrite. There's more on Yii 3 at the very end of this announcement.

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

Huge thanks to all Yii community members who contribute to the framework. It wouldn't have been possible without you. Additional thanks to translators who are keeping international documentation up to date.

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

You can also discuss this news on our forum.

Below we summarize some of the enhancements and changes that slipped into this release. A complete list of changes can be found in the CHANGELOG.

Active Record

A behavior for optimistic locking was added by Salem Ouerdani, @tunecino.

Optimistic locking allows multiple users to access the same record for edits and avoids potential conflicts. In case when a user attempts to save the record upon some staled data (because another user has modified the data), a StaleObjectException exception will be thrown, and the update or deletion is skipped.

The locking itself was implemented from the first versions of Yii but using it properly wasn't easy. Now it is. You can find details in the guide section on optimistic locks and in OptimisticLockBehavior itself.

Migrations

Console migration generator defaults were changed so that the migrations are generated with table prefixes used. If you want to disable this behavior, set yii\console\controllers\MigrateController::useTablePrefix to false via console command mappings.

Databases

  • The MySQL driver now supports fractional seconds for time types (require MySQL >= 5.6.4).
  • The Oracle driver now supports resetting sequences.

Helpers

  • yii\helpers\Inflector now works correctly with UTF-8.
  • Added yii\mutex\FileMutex::$isWindows for Windows file shares on Unix guest machines.
  • yii\helpers\UnsetArrayValue, yii\helpers\ReplaceArrayValue object can now be restored after serialization using var_export() function.

GridView

Added $filterOnFocusOut option that allows to toggle if filtering should be triggerd when filter field is losing focus.

jQuery

jQuery 3.3 is now allowed to be installed.

Mutex

  • Increased frequency of lock tries for yii\mutex\FileMutex::acquireLock() when $timeout is provided.
  • Added support for $timeout in yii\mutex\PgsqlMutex::acquire().

Security fixes

Two security issues were fixed in this release:

  • CVE-2018-14578: CSRF token check bypassing in \yii\web\Request::getMethod()
  • CVE-2018-19454: Excess logging of sensitive information in \yii\log\Target

Project templates

Codeception configs were cleaned up in both basic and advanced project templates.

A basic Docker configuration was added to the Advanced project template, allowing you to quickly start developing. Advanced template tests require newer version of Codeception that works starting with PHP 7.0. Old applications will work with older versions of Codeception so there's no need for upgrade if you don't want it.

A bit about Yii 3.0

Yii 3 will be the next major version of the Yii framework. A separate announcement will be made subsequently, but here's a brief overview of the future:

A new architecture: The Yii framework has been split into several packages. This will allow you to pick the packages you need to compose your Yii application instead of installing one package that provides everything.

JavaScript-agnostic: With the reorganization of the source code, Yii will no longer tie you to a specific JavaScript framework. Core features of Yii have been rewritten to be jQuery-free.

PSR Compatibility: Yii 3 will embrace the PHP-FIG recommendations, and implement many PSRs: Logging, Caching, DI, etc.

Yii 3.0 is currently being developed. We will make separate announcements when it reaches alpha stability.

]]>
0
[news] Bootstrap extension version 2.0.9 released Tue, 29 Jan 2019 21:51:44 +0000 https://www.yiiframework.com/news/195/bootstrap-extension-version-2-0-9-released https://www.yiiframework.com/news/195/bootstrap-extension-version-2-0-9-released samdark samdark

We are very pleased to announce the release of Bootstrap extension version 2.0.9 which updates asset constraint to use Bootstrap 3.4.x.

]]>
0
[news] Bootstrap 4 extension version 2.0.0 released Tue, 29 Jan 2019 12:50:12 +0000 https://www.yiiframework.com/news/194/bootstrap-4-extension-version-2-0-0-released https://www.yiiframework.com/news/194/bootstrap-4-extension-version-2-0-0-released samdark samdark

We are very pleased to announce the first stable release of Bootstrap 4 extension version 2.0.0 that adds assets and widgets for Bootstrap 4.

The guide is available at the website.

]]>
0
[news] Auth Client extension 2.1.8 released Mon, 28 Jan 2019 18:56:30 +0000 https://www.yiiframework.com/news/193/auth-client-extension-2-1-8-released https://www.yiiframework.com/news/193/auth-client-extension-2-1-8-released samdark samdark

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

It fixes a redirect bug in LinkedIn provider, changes Google client to use Google Sign-in API instead of Google Plus and adds two enhancements for AuthAction:

  • Ability to configure user component used.
  • Ability to to pass buildAuthUrl params to OAuth flows.

See the CHANGELOG for details.

]]>
0
[news] Shell extension 2.0.2 released Mon, 07 Jan 2019 21:34:06 +0000 https://www.yiiframework.com/news/192/shell-extension-2-0-2-released https://www.yiiframework.com/news/192/shell-extension-2-0-2-released samdark samdark

We are very pleased to announce the release of Shell extension version 2.0.2.

This version bumps psy/psysh dependency to ~0.9.3.

]]>
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
[news] PHP 7.3.0 released Sat, 08 Dec 2018 10:02:10 +0000 https://www.yiiframework.com/news/191/php-7-3-0-released https://www.yiiframework.com/news/191/php-7-3-0-released samdark samdark

The PHP development team released version 7.3.0 that comes with numerous improvements and new features such as

The list of changes is recorded in the ChangeLog. The migration guide is available in the PHP Manual.

Both Yii 2.0 and upcoming Yii 3.0 releases will be comatible with new PHP release.

]]>
0
[news] Gii extension 2.0.8 released Sat, 08 Dec 2018 10:21:58 +0000 https://www.yiiframework.com/news/190/gii-extension-2-0-8-released https://www.yiiframework.com/news/190/gii-extension-2-0-8-released samdark samdark

We are very pleased to announce the release of Gii extension version 2.0.8.

Additionally to bug fixes, there is a new option in model generator that allows standardized capitals in class names:

SOME_TABLE -> SomeTable
Other_Table -> OtherTable

instead of

SOME_TABLE -> SOMETABLE
Other_Table -> OtherTable

See the CHANGELOG for details.

]]>
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
[news] ApiDoc extension version 2.1.1 released Wed, 14 Nov 2018 14:24:29 +0000 https://www.yiiframework.com/news/189/apidoc-extension-version-2-1-1-released https://www.yiiframework.com/news/189/apidoc-extension-version-2-1-1-released CeBe CeBe

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

This release fixes some issues with wrongly formatted PHPDoc and includes support for {@inheritdoc} tags. It also improves Guide rendering by adding a table of contents if there is more than one headline.

Markdown code highlighting has been extracted into a trait MarkdownHighlightTrait, which can be re-used in different contexts.

See the CHANGELOG for a full list of changes.

You may discuss this release on the forum.

]]>
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
[news] Sphinx extension 2.0.11 released Tue, 26 Mar 2019 02:03:37 +0000 https://www.yiiframework.com/news/187/sphinx-extension-2-0-11-released https://www.yiiframework.com/news/187/sphinx-extension-2-0-11-released samdark samdark

We are very pleased to announce the release of Sphinx extension version 2.0.11. In this release there is a bug fixed that yii\sphinx\ActiveQuery::all() was unable to follow instructions given by method indexBy().

See the CHANGELOG for details.

]]>
0
[news] Twig extension 2.2.1 released Tue, 26 Mar 2019 02:03:37 +0000 https://www.yiiframework.com/news/186/twig-extension-2-2-1-released https://www.yiiframework.com/news/186/twig-extension-2-2-1-released samdark samdark

We are very pleased to announce the release of Twig extension version 2.2.1. This release fixes an error when outputting DateTime dates.

See the CHANGELOG for details.

]]>
0
[news] Swiftmailer extension 2.1.2 released Sun, 23 Sep 2018 22:04:27 +0000 https://www.yiiframework.com/news/185/swiftmailer-extension-2-1-2-released https://www.yiiframework.com/news/185/swiftmailer-extension-2-1-2-released samdark samdark

We are very pleased to announce the release of Swiftmailer extension version 2.1.2. This release brings automatic transport restart and adds an ability to specify the disposition of an attachment by supplying a setDisposition value when embedding content in a message.

See the CHANGELOG for details.

]]>
0
[news] HTTP client extension 2.0.7 released Sun, 23 Sep 2018 21:57:52 +0000 https://www.yiiframework.com/news/184/http-client-extension-2-0-7-released https://www.yiiframework.com/news/184/http-client-extension-2-0-7-released samdark samdark

We are very pleased to announce the release of HTTP client extension version 2.0.7. In this release, Response::detectFormatByContent was fixed to properly detect JSON Array. Additionally, Request::setFullUrl() method was added.

See the CHANGELOG for details.

]]>
0
[news] Debug extension 2.0.14 released Sun, 23 Sep 2018 22:38:01 +0000 https://www.yiiframework.com/news/183/debug-extension-2-0-14-released https://www.yiiframework.com/news/183/debug-extension-2-0-14-released samdark samdark

We are very pleased to announce the release of Debug extension version 2.0.14. In this release, additionally to bugfixes, there's new "Events" panel.

See the CHANGELOG for details.

]]>
0
[wiki] Update and Delete buttons on Breadcrumb Tue, 26 Mar 2019 02:03:37 +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 Tue, 26 Mar 2019 02:03:37 +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
[wiki] Yii2 Report Grid Mon, 26 Mar 2018 10:10:29 +0000 https://www.yiiframework.com/wiki/860/yii2-report-grid https://www.yiiframework.com/wiki/860/yii2-report-grid chrisb34 chrisb34

A Yii2 Gridview designed specifically for reporting

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

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

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

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

Why is this significant

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

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

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

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

or add:

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

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

php composer.phar update

to get the updated package on your application install.

Widget Setup

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

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

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

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

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

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

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

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

Usage

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

Column Configuration

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

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

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

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

Usage

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

for more info see: yii2.percipero.com

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

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

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

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

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

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

My method for handling sub-domains

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

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

common/config/bootstrap.php

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

Create common/components/UrlManager.php

<?php
namespace common\components;

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

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

    protected $_hostInfo;

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

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

        return $domain;
    }

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

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

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

}

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

Add this to your config under the components array:

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

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

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

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

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

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

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

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

or to get the SQL with all parameters included try:

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

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

]]>
0