Live News for Yii Framework News, fresh extensions and wiki articles about Yii framework. Thu, 21 Nov 2019 13:09:05 +0000 Zend_Feed_Writer 2 (http://framework.zend.com) https://www.yiiframework.com/ [news] Yii 2.0.30 Wed, 20 Nov 2019 12:27:54 +0000 https://www.yiiframework.com/news/265/yii-2-0-30 https://www.yiiframework.com/news/265/yii-2-0-30 samdark samdark

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

Version 2.0.30 is a minor release of Yii 2.0 that fixes a number of bugs.

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

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

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

]]>
0
[news] MongoDB extension 2.1.9 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/264/mongodb-extension-2-1-9-released https://www.yiiframework.com/news/264/mongodb-extension-2-1-9-released samdark samdark

We are very pleased to announce the release of MongoDB extension version 2.1.9 that fixes Collection::dropAllIndexes() error when no indexes were dropped.

]]>
0
[news] Smarty extension 2.0.9 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/263/smarty-extension-2-0-9-released https://www.yiiframework.com/news/263/smarty-extension-2-0-9-released samdark samdark

We are pleased to announce the release of Smarty extension version 2.0.9. In this release {js} function was added allowing to instantiate yii\web\JsExpression:

{js assign='expr' expression='function(){alert('expression');}}'}
]]>
0
[news] Gii extension 2.1.2 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/262/gii-extension-2-1-2-released https://www.yiiframework.com/news/262/gii-extension-2-1-2-released samdark samdark

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

This release fixes issue with RTL naming for foreign keys such as id_user that was causing problems in generated code.

Also, it improves some aspects of generated code. float types are now recognized and generated and annotations for nullable types are now there:

/**
 * @property string|null $car_number
 */

See the CHANGELOG for details.

]]>
0
[news] Debug extension 2.1.12 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/261/debug-extension-2-1-12-released https://www.yiiframework.com/news/261/debug-extension-2-1-12-released samdark samdark

Debug extension version 2.1.12 was released. This release fixes missing timeline panel tooltips and adds a warning message in DB panel when traceLevel is too low in order for it to collect data.

See the CHANGELOG for details.

]]>
0
[news] Auth Client extension 2.2.6 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/260/auth-client-extension-2-2-6-released https://www.yiiframework.com/news/260/auth-client-extension-2-2-6-released samdark samdark

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

This release adds CacheStateStorage that provides state storage based in cache component.

Additionally, request option for turning off SSL peer verification was removed to make extension more secure by default. It may break your application if server doesn't have root certificates set up correctly so make sure to check upgrade guide.

See the CHANGELOG for details.

]]>
0
[extension] daxslab/yii2-calendly Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/daxslab/yii2-calendly https://www.yiiframework.com/extension/daxslab/yii2-calendly glpzzz glpzzz

yii2-calendly

  1. Installation
  2. Usage
  3. Defaults

Build Status Latest Stable Version Total Downloads Latest Unstable Version License

Embeds Calendly widgets into Yii2 applications

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist daxslab/yii2-calendly "*"

or add

"daxslab/yii2-calendly": "*"

to the require section of your composer.json file.

Usage

<?= \daxslab\calendly\Calendly::widget([
    'calendlyId' => Yii::$app->params['calendlyId'],
    'mode' => \daxslab\calendly\Calendly::MODE_INLINE,
]) ?>

Defaults

The component will try to set some properties by default:

  • mode: Defaults to "inline". It can also be "button" or "text"
  • text: Default to "Schedule time with me"

Proudly made by Daxslab.

]]>
0
[extension] floor12/yii2-module-backup Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/floor12/yii2-module-backup https://www.yiiframework.com/extension/floor12/yii2-module-backup floor12 floor12

yii2-module-backup

  1. Installation
  2. Usage

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

Этот файл доступен на русском языке.

This module helps to create and restore backups of databases and files stored on disk. It has web-interface, console commands, and REST-API for remote control. It also supports io-priority settings and has flexible configuration options. To work independent of the application database, this module uses its sqlite database in the backup folder.

i18n

Now, this module supports English and Russian languages.

Yii backup module

Installation

To add this module to your app, just run:

`bash $ composer require floor12/yii2-module-backup or add this to the `require` section of your composer.json. json "floor12/yii2-module-backup": "dev-master" `

After that, include minimal module configuration in modules section of application config: `php
'modules' => [

         'backup' => [
             'class' => 'floor12\backup\Module',
             'administratorRoleName' => '@',
             'configs' => [
                 [
                     'id' => 'main_db',
                     'type' => BackupType::DB,
                     'title' => 'Main database',
                     'connection' => 'db',
                     'limit' => 10
                 ],
                 [
                     'id' => 'main_storage',
                     'type' => BackupType::FILES,
                     'title' => 'TMP folder',
                     'path' => '@app/tmp',
                     'limit' => 2
                 ]
             ]
         ]
         ],
     ],
 ...

`

These parameters is possible to set up:

  • administratorRoleName - role to access web controller
  • backupFolder - path alias to the place where backups are stored (default is @app/backups)
  • chmod - if this param has value, the new backup file will change mode after creation
  • authTokens - array of auth tokens to use REST-API of the module
  • ionice - the value of this param will be placed before ZIP console command in case of disk backup (for example it's possible to put iotince -c3 inside this param to run backup creation with IDLE disk i/o priority)
  • adminLayout - it will change default main layout to something you need (if your admin panel has different base layout)

And the main and required param isconfigs - its an array of your backup items (folders and databases). Each backup items mast have this elements to set:

  • id - backup identifier, contains only letters and numbers without space
  • type - type backup: disk or database
  • title - human-readable backup item title to show in the admin interface
  • limit - how many backup copies keep before delete (0 - never delete old copies)
  • connection - in case of database backup, connection name in Yii2 config
  • path - in case of disk backup, the path to store backup files

Usage

WEB interface

This module has a web controller to work with backups. Go to backup/admin or backup/admin/index to create, delete, restore and download backups.

### Console interface

To list all existing backups run `bash $ ./yii backup/console/index> `

To create config run `bash $ ./yii backup/console/create ` backup_config_id is backup item identifier from module configuration.

To restore config run `bash $ ./yii backup/console/restore ` backup_id is identifier of backup stored in sqlite database

REST-api

By default, rest controller takes place on the route /backup/api. To get access to it, add header Backup-Auth-Token to request with one of the tokens stored in application config in the module section (param authTokens);

Get list of backups

GET /backup/api/index

This is useful to remote backup checks from some dashboard with a few projects.

Response example: `json [ {

"id": 8,
"date": "2019-11-11 07:02:23",
"status": 1,
"type": 1,
"config_id": "main_storage",
"config_name": "TMP folder",
"filename": "main_storage_2019-11-11_07-02-23.zip",
"size": 4183

}, {

"id": 7,
"date": "2019-11-11 06:56:36",
"status": 1,
"type": 0,
"config_id": "main_db",
"config_name": "Main database",
"filename": "main_db_2019-11-11_06-56-36.gz",
"size": 753

},

] `

Create new backup

POST /backup/api/backup?config_id=<backup_config_id>

Succes respons example: `json {"result":"success"} `

Restore from backup

POST /backup/api/restore?id=<backup_id>

Succes respons example: `json {"result":"success"} `

Delete backup

DELETE /backup/api/delete?id=<backup_id>

Succes respons example: `json {"result":"success"} `

Get backup file

GET /backup/api/get?id=<backup_id>

This request will return backup archive with requested ID.

]]>
0
[extension] floor12/yii2-module-files Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/floor12/yii2-module-files https://www.yiiframework.com/extension/floor12/yii2-module-files floor12 floor12

yii2-module-files

  1. About the module
  2. Usage
  3. Contributing

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

Этот файл доступен на русском языке.

About the module

FileInputWidget

This module was designed to solve the problem of creating file fields in ActiveRecord models of the Yii2 framework. The main components of the module are:

  • floor12\files\components\FileBehaviour - behavior that must be connected to the ActiveRecord model;
  • floor12\files\components\FileInputWidget - an InputWidget that allows you to add, edit and generally work with files;
  • floor12\files\components\FileListWidget - an additional widget to display a list of files with the abilities to view images in the Lightbox2 gallery, download all files of the current field in zip format, and view the Word and Excel files using the Microsoft office online.
Key features
  • adding one or more fields with files to the ActiveRecord model;
  • setting up validation of these fields using the standard FileValidator defined in the rules ()section;
  • in the case of working with images - the ability to configure the image ratio (in this case, when loading an image through the FileInputWidget widget will automatically open a modal window to crop the image with the desired ratio);
  • thumbnails creating with optimal sizes for each case in site template. Also, these thumbnails supports WEBP format;
  • download files in ZIP-format
  • FileInputWidget supports changing of files order by drag-and-drop, cropping and filename updating;
  • in case of drag-and-drop uploading, the file result file order is the same as on client folder;
  • automatic horizon detection by EXIF ​​tag;
  • if you need to add images to the model not with the web interface of the site, but using console parsers and other similar cases - its possible. For this case, the module includes two classes: FileCreateFromInstance and FileCreateFromPath with helps add files to AR model from server file system;
  • in case of video files: recoding them to h264 using the ffmpeg utility;
i18n

At this stage, the module supports the following languages:

  • English
  • Russian  
    Principle of operation

    All files data is stored in the file table. The file model relay to the model by three fields:

  • class - the full class name of the relay model
  • field - the name of the model field
  • object_id - primary key of the model

When file added to the form, it uploads to server in background where all processing takes place. As a result of this processing, it is written to disk and a new entry is created for it in the file table, with the fields class and field filled with data from the model, and object_id is empty and will assign only after saving the ActiveRecord model.  When a file is deleted from the widget, it is not deleted from the disk and the file table, just obejct_id equals to 0. You can use the console command files / console / clean to periodically clean up this kind of orphan files.

## Install and setup

To add this module to your app, just run:

`bash $ composer require floor12/yii2-module-files or add this to the `require` section of your composer.json. json "floor12/yii2-module-files": "dev-master" `

Then execute a migration to create file table. `bash $ ./yii migrate --migrationPath=@vendor/floor12/yii2-module-files/src/migrations/ `

After that, include module data in modules section of application config: `php
'modules' => [

         'files' => [
             'class' => 'floor12\files\Module',
             'storage' => '@app/storage',
             'cache' => '@app/storage_cache',
             'token_salt' => 'some_random_salt',
         ],
     ],
 ...

`

Parameters to set:

  • storage - the path alias to the folder to save files and image sources, by default it is located in the storage folder in the project root;
  • cache - path alias to the folder of thumbnails of images that the module creates on the fly upon request and caches;
  • token_salt - a unique salt to generate InputWidget tokens.    

    Usage

    Work with ActiveRecord Model

    To add one or more files fields to the ActiveRecord model, you need to connect floor12\files\components\FileBehaviour to it and pass list the field names that will store the files in the model. For example, for the User model, 2 file fields are defined here : avatar and documents: `php public function behaviors() {

    return [
        'files' => [
            'class' => 'floor12\files\components\FileBehaviour',
            'attributes' => [
                'avatar',
                'documents'
            ],
        ],
        ...
    

    To have nice attribute labels in forms, add some labels to `attributeLabels()`: php public function attributeLabels() {

       return [
           ...
           'avatar' => 'Аватар',
           'documents' => 'Документы',
           ...
       ];
    

    } `

Setup validation rules in the rules() method of ActiveRecord model: `php public function rules() {

 return [
     // Avatar is required attribute 
     ['avatar', 'required'],
     
     // Avatar allow to uploade 1 file with this extensions: jpg, png, jpeg, gif
     ['avatar', 'file', 'extensions' => ['jpg', 'png', 'jpeg', 'gif'], 'maxFiles' => 1], 

     // Documens allows to upload a few files with this extensions: docx, xlsx
     ['documents', 'file', 'extensions' => ['docx', 'xlsx'], 'maxFiles' => 10],
 ...    

` ### Work with files

If maxFiles in FileValidator equals to 1, this attribute will store an floor12\files\models\File object. Example: `php // The href field contains web path to file source echo Html::img($model->avatar->href)

// __toString() method of File object will return href as well echo Html::img($model->avatar)
`

If the file is image, getPreviewWebPath method returns a web path to image thumbnail. By default thumbnail created with the jpeg or png format, it depends to source file. But also WEBP option is available.

File::getPreviewWebPath(int $width = 0, int $height = 0 ,bool $webp = false)

Usage example: `php // User avatar thumbnail with 200px width echo Html::img($model->avatar->getPreviewWebPath(200));

// User avatar thumbnail with 200px width and WEBP format echo Html::img($model->avatar->getPreviewWebPath(200, 0, true));

// User avatar thumbnail with 300px height and WEBP format echo Html::img($model->avatar->getPreviewWebPath(0, 300, true));
`

When maxFiles equals to 1, multiple upload is available. In this case, model field will contains an array if floor12\files\models \File objects: `php foreach ($model->docs as $doc}

 Html::a($doc->title, $doc->href);

`

Here is another example, the advanced usage of thumbnails. In this case, we use modern picture and source tags, as well as media queries. As a result, we have 8 different thumbnails: 4 has webp format for those browsers that support this it, and 4 has jpeg format. Devices with retina displays will get an images with double resolution, regular screens have regular sized pictures. This example also uses different images widths at different screen widths (just as example of mobile/desktop image switching): `php

 <source type="image/webp" media='(min-width: 500px)' srcset="
                          <?= $model->poster->getPreviewWebPath(150, 0, 1) ?> 1x,
                          <?= $model->poster->getPreviewWebPath(300, 0, 1) ?> 2x">
 <source type="image/webp" media='(max-width: 500px)' srcset="
                          <?= $model->poster->getPreviewWebPath(350, 0, 1) ?> 1x,
                          <?= $model->poster->getPreviewWebPath(700, 0, 1) ?> 2x">
 <source type="image/jpeg" media='(min-width: 500px)' srcset="
                          <?= $model->poster->getPreviewWebPath(150, 0, 0) ?> 1x,
                          <?= $model->poster->getPreviewWebPath(300, 0, 0) ?> 2x">
 <img src="<?= $model->poster->getPreviewWebPath(150) ?>" 
      srcset=" 
            <?= $model->poster->getPreviewWebPath(350) ?> 1x, 
            <?= $model->poster->getPreviewWebPath(700) ?> 2x"
      alt="<?= $model->title ?>">

`

### Listing the files There is a widget for listing all files. It supports Lightbox2 gallery to display images and MS Office files preview. Its also supports downloading of the all the files attached to the field in a ZIP-archive.

`php echo \floor12\files\components\FileListWidget::widget([

 'files' => $model->docs, 
 'downloadAll' => true, 
 'zipTitle' => "Documents of {$user->fullname}" 

]) ` An array of File objects must be passed to the widget files field. Also additional parameters available:

  • title - optionally set the title of the block (by default its taken from AttributeLabels())",
  • downloadAll - show the "download all" button,
  • zipTitle - set the file name of zip archive,
  • passFirst - skip first file in array (it is often necessary to display the gallery without the first picture. For example, in the news view page, when the first image used to be news main image).

FileInputWidget

### InputWidget for ActiveFrom

To display files block in your forms use the floor12\files\components\FileInputWidget:

`php <?= $form->field($model, 'avatar')->widget(floor12\files\components\FileInputWidget::class) ?> ` Moreover, if maxFiles parameter in FileValidator equals to 1 or more, FileInputWidget will take the necessary form to load one file or several at once. If necessary, you can pass uploadButtonText and uploadButtonClass parameters to the widget.

Contributing

I will be glad of any help in the development, support and bug reporting of this module.

]]>
0
[extension] coderius/yii2-pell-widget Sat, 09 Nov 2019 13:16:19 +0000 https://www.yiiframework.com/extension/coderius/yii2-pell-widget https://www.yiiframework.com/extension/coderius/yii2-pell-widget coderius coderius

Pell content WYSIWYG editor Widget for Yii2

  1. Installation
  2. Usage
  3. Examples widget usage
  4. Testing
  5. Further Information
  6. Contributing
  7. Credits
  8. License

Latest Version Software License Code Coverage Code Quality Code Intelligence Status Build Status Build Status travis

Renders a Pell WYSIWYG text editor plugin widget.

Live demo

Installation

The preferred way to install this extension is through composer.

Either run

composer require coderius/yii2-pell-widget:"~1.0"

or add

"coderius/yii2-pell-widget" : "~1.0"

to the require section of your application's composer.json file.

Usage

For example to use the pell editor with a model:

`php echo Pell::widget([

'model' => $model,
'attribute' => 'text',

]); `

Inside form without model:

`php $value = 'textarea some content';

echo \coderius\pell\Pell::widget([

'name' => 'textarea-name',
'value'  => $value,
'clientOptions' =>[]

]); `

The following example will used not as an element of form:

`php echo Pell::widget([

'asFormPart'  => false,
'value'  => $value,
'clientOptions' =>[
    'onChange' => new JsExpression(
        "html => {
            console.log(html);
        },"
    )
]

]); `

You can also use this widget in an ActiveForm using the widget() method, for example like this:


use coderius\pell\Pell;

<?= $form->field($model, 'text')->widget(Pell::className(), []);?>
About ClientOptions

Please, remember that if you are required to add javascript to the configuration of the js plugin and is required to be plain JS, make use of JsExpression. That class was made by Yii for that specific purpose. For example:

// Having the following scenario
<script> 
    function jsFunctionToBeCalled() {
        // ...
    }
</script>

<?= $form->field($model, 'content')->widget(Pell::className(), [
        'clientOptions' => [
            'defaultParagraphSeparato' => 'div',

            // ...

            'actions' => [
                'bold',
                'italic',
                'underline',
                'strikethrough',
                'heading1',
                'heading2',
                'paragraph',
                'quote',
                'olist',
                'ulist',
                'code',
                'line',
                'link',
                'image',
                [
                    'name'   => 'backColor',
                    'icon'   => '<div style="background-color:pink;">A</div>',
                    'title'  => 'Highlight Color',
                    // this will render the function name without quotes on the configuration options of the plugin
                    'result' => new JsExpression('jsFunctionToBeCalled')
                ],
            ],
            
            // ...
        ]
        
    ]
]); ?>

Examples widget usage

Please see Examples usage in yii2 view files for more examples.

Testing

$ phpunit

Further Information

Please, check the Pell plugin github documentation for further information about its configuration options.

Contributing

Please see CONTRIBUTING for details.

Credits

License

The MIT License (MIT). Please see License File for more information.

Web development has never been so fun!
coderius.biz.ua

]]>
0
[news] Redis extension 2.0.11 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/259/redis-extension-2-0-11-released https://www.yiiframework.com/news/259/redis-extension-2-0-11-released samdark samdark

We are very pleased to announce the release of Redis extension version 2.0.11.

This version adds for Redis cluster contributed by Robert Hofer.

See the CHANGELOG for details.

]]>
0
[news] Auth Client extension 2.2.5 released Tue, 05 Nov 2019 14:26:17 +0000 https://www.yiiframework.com/news/258/auth-client-extension-2-2-5-released https://www.yiiframework.com/news/258/auth-client-extension-2-2-5-released samdark samdark

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

In this release deprecated dependency spomky-labs/jose was replaced by JWT Framework.

See the CHANGELOG for details.

]]>
0
[news] Debug extension 2.1.11 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/257/debug-extension-2-1-11-released https://www.yiiframework.com/news/257/debug-extension-2-1-11-released samdark samdark

Debug extension version 2.1.11 was released. It is adding removal of stale debug data, fixes issues and adding buttons for navigating between requests.

See the CHANGELOG for details.

]]>
0
[extension] diggindata/yii2-geonames Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/diggindata/yii2-geonames https://www.yiiframework.com/extension/diggindata/yii2-geonames jwerner jwerner

GeoNames Extension for Yii 2

  1. 1. Installation
  2. 2. Configuration
  3. 3. Update Database Schema
  4. Download Data
  5. Import Data
  6. Delete duplicate postal codes

This extension provides a GeoNames management solution for Yii framework 2.0, containing import scripts and a CRUD UI.

It is an adaption of the Laravel / Lumen / Eloquent Geonames scripts at https://github.com/yurtesen/geonames

For license information check the LICENSE-file.

Latest Stable Version

1. Installation

The preferred way to install this extension is through composer.

Either run

composer require --prefer-dist diggindata/yii2-geonames:dev-master

or

php composer.phar require --prefer-dist diggindata/yii2-geonames

or add

"diggindata/yii2-geonames": "@dev"

to the require section of your composer.json, then run

composer install

2. Configuration

Folders

We need a folder to store downloaded data files from geonames.org. So in your application's base directory, create the directories data and data/geonames. This directory will hold the downloaded data files from geonames.org.

Application Configuration

Add following lines to both, your web and your console configuration file to enable this module (config/web.php and config/console.php):

    ...
    'modules' => [
        ...
        'geonames' => [
            'class' => 'diggindata\geonames\Module',
        ],
    ],
Commandline Configuration

The yii geonames shell command can be configured.

Create a file geonames.php in the config directory of your Yii application.

You may use the file vendoe/diggindata/yii2-geonames/geonames.php.example file as a template.

All available configuration options are listed below with their default values.

proxy_user (type: string, default: null)
proxy_pass (type: string, default: null)
keepTxt (type: boolean, default: true)
storagePath (default: Yii::getAlias('@app/data') . '/geonames')
ignoreTables

Array of tables which would be ignored in imports. Some tables might note be used by you, e.g. alternate_names table.
Uncommenting it will stop auto-import.

countries (type: array, default: array())

Array of 2-Char ISO codes of countries which shall be imported. If the array is empty, the allCountries file is imported.

3. Update Database Schema

Finally you need to update your database schema by applying the provided migrations. Make sure that you have properly configured your db application component, then run the following command:

$ php yii migrate/up --migrationPath=@vendor/diggindata/yii2-geonames/src/migrations

Where do I go now?

  1. 1. Installation
  2. 2. Configuration
  3. 3. Update Database Schema
  4. Download Data
  5. Import Data
  6. Delete duplicate postal codes

By now you should have Yii2-geonames installed. You may now open the geonames module. You should also be able to import geonames data via the console commqand, see Usagebelow.

Usage

  1. 1. Installation
  2. 2. Configuration
  3. 3. Update Database Schema
  4. Download Data
  5. Import Data
  6. Delete duplicate postal codes

Download Data

Enter the following command within your application's folder:

yii geonames/geonames/download

This will download data files:

[] zip
+--- DE.zip
iso-languagecodes.txt
timeZones.txt
admin1CodesASCII.txt
admin2Codes.txt
countryInfo.txt
DE.zip
featureCodes_en.txt
hierarchy.zip

Import Data

Enter the following command within your application's folder:

yii geonames/geonames/seed

This will insert the downloaded data into the respective database tables.

Tipps

  1. 1. Installation
  2. 2. Configuration
  3. 3. Update Database Schema
  4. Download Data
  5. Import Data
  6. Delete duplicate postal codes

Delete duplicate postal codes

-- Add Auto-Increment PK
ALTER TABLE `postalcode`
ADD `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY;

-- Delete duplicates
DELETE t1 FROM postalcode t1
INNER JOIN postalcode t2 
WHERE 
    t1.id > t2.id AND (
    t1.countryCode = t2.countryCode AND
    t1.postalCode = t2.postalCode AND
    t1.placeName = t2.placeName AND
    t1.admin1Code = t2.Admin1Code AND
    t1.admin2Code = t2.admin2Code AND
    t1.admin3Code = t2.admin3Code AND
    t1.latitude = t2.latitude AND
    t1.longitude = t2.longitude
);

-- Drop Auto-Increment PK
ALTER TABLE postalcode DROP `id`;
]]>
0
[extension] floor12/yii2-metamaster Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/floor12/yii2-metamaster https://www.yiiframework.com/extension/floor12/yii2-metamaster floor12 floor12

yii2-metamaster

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

Этот файл так же доступен на русском языке.

This is a component for generate some Meta, Open Graph and Twitter-card tags in a template header of Yii2 app.

This is a list of supported tags:

  • canonical
  • head title
  • meta description
  • meta keywords
  • og:sitename
  • og:type
  • og:url
  • og:title
  • og:description
  • og:image
  • og:image:width
  • og:image:height
  • twitter:card
  • twitter:domain
  • twitter:site
  • twitter:description
  • twitter:image:src
  • itemprop:name
  • itemprop:image

Installation

Just run: `bash $ composer require floor12/yii2-metamaster or add this to the require section of your composer.json.json "floor12/yii2-metamaster": "dev-master" `

After that, include some basic metamaster data into components section of application config. `php

'components' => [
    'metamaster' => [
        'class' => 'floor12\metamaster\MetaMaster',
        'siteName' => 'My cool new Web Site',
        'defaultImage' => '/design/export_logo.png',
    ],
...

Attributes:
1. `siteName` - name of project to show in Open Graph tags;
2. `defaultImage` - web relative path to default image for Open Graph tags;
3. `web` - yii2 alias to web path to read image width and height for Open Graph tags (default is `@app/web`)
4. `protocol` - default protocol to generate links (default is `https`)


Usage
------------

Its possible to use in any place of your app. Just use setters and then call the `register(View $view)` method with View object passed into it.

Allowed setters:
```php
Metamaster::setSiteName(string $value)
Metamaster::setTitle(string $value)
Metamaster::setUrl(string $value)
Metamaster::setType(string $value)
Metamaster::setDescription(string $value)
Metamaster::setImage(string $relativePath, string $absolutePath = null)

For example, using in controller:

public function actionIndex()
   {
        Yii::$app->metamaster
                   ->setTitle("This is test page")
                   ->setDescription("This is page description")
                   ->setImage('/images/article/image.png')
                   ->register(Yii::$app->getView());
                   
        return $this->render('index');
    }
      

It will generate all you need in template: `html

This is test page` ]]>
0
[extension] daxslab/yii2-facebookcomments-widget Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/daxslab/yii2-facebookcomments-widget https://www.yiiframework.com/extension/daxslab/yii2-facebookcomments-widget glpzzz glpzzz

Yii2 Facebook Comments

  1. Installation
  2. Usage

Latest Stable Version Total Downloads Latest Unstable Version License

Yii2 widget to include the Facebook widget for comments in views.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist daxslab/yii2-facebookcomments-widget "*"

or add

"daxslab/yii2-facebookcomments-widget": "*"

to the require section of your composer.json file.

Usage

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

<?= \daxslab\facebook\CommentsBox::widget([
    'appId' => 'MY_FACEBOOK_APP_ID', //defaults to Yii::$app->paramss['facebook_app_id']
    'numPosts' => 10 //defaults to 5
]); ?>
]]>
0
[extension] daxslab/yii2-thumbnailer Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/daxslab/yii2-thumbnailer https://www.yiiframework.com/extension/daxslab/yii2-thumbnailer glpzzz glpzzz

Yii2 Thumbnailer

  1. Installation
  2. Configuration
  3. Usage

Build Status Latest Stable Version Total Downloads Latest Unstable Version License

Yii2 component to generate image thumnails of any size.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist daxslab/yii2-thumbnailer "*"

or add

"daxslab/yii2-thumbnailer": "*"

to the require section of your composer.json file.

Configuration

The basic configuration only requires adding the component to the application:

'components' => [
    //...
    'thumbnailer' => [
        'class' => 'daxslab\thumbnailer\Thumbnailer',
    ],
    //...
]

Besides that a default value is always provided, all the options can be configured.

'components' => [
    //...
    'thumbnailer' => [
        'class' => 'daxslab\thumbnailer\Thumbnailer',
        'defaultWidth' => 500,
        'defaultHeight' => 500,
        'thumbnailsBasePath' => '@webroot/assets/thumbs',
        'thumbnailsBaseUrl' => '@web/assets/thumbs',
        'enableCaching' => true, //defaults to false but is recommended
    ],
    //...
]

Usage

Once the extension is configured, simply use it in your views by:

//Generates thumbnail with default values specified in the configuration
Html::img(Yii::$app->thumbnailer->get($imageUrl));

//Generates a 400px width thumbnail. The height is determined as the width because is not set. 
Html::img(Yii::$app->thumbnailer->get($imageUrl, 400));

//Generates a 400x400 pixels thumbnail and 60% quality 
Html::img(Yii::$app->thumbnailer->get($imageUrl, 400, 400));

//Generates a 400x400 pixels thumbnail and 10% quality
Html::img(Yii::$app->thumbnailer->get($imageUrl, 400, 400, 10));

//Generates a 400x400 pixels thumbnail, 10% quality and not cropping the image
//but inserting it into a box with the specified dimensions.
Html::img(Yii::$app->thumbnailer->get($imageUrl, 400, 400, 10, ManipulatorInterface::THUMBNAIL_INSET));

Proudly made by Daxslab.

]]>
0
[extension] daxslab/yii2-taggedview Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/daxslab/yii2-taggedview https://www.yiiframework.com/extension/daxslab/yii2-taggedview glpzzz glpzzz

TaggedView

  1. Installation
  2. Configuration
  3. Defaults
  4. Usage

Build Status Latest Stable Version Total Downloads Latest Unstable Version License

Extension to help setup the standard HTML meta tags besides the ones defined by Opengraph and TwitterCard to contribute to website SEO

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist daxslab/yii2-taggedview "*"

or add

"daxslab/yii2-taggedview": "*"

to the require section of your composer.json file.

Configuration

Configure the View component into the main configuration file of your application:

'components' => [
    //...
    'view' => [
        'class' => 'daxslab\taggedview\View',
        //configure some default values that will be shared by all the pages of the website
        //if they are not overwritten by the page itself
        'image' => 'http://domain.com/images/default-image.jpg',
    ],
    //...
]

Defaults

The component will try to set some properties by default:

$this->site_name = Yii::$app->name;
$this->url = Yii::$app->request->baseUrl;
$this->locale = Yii::$app->language;

You can overwrite the content of this tags in every page or in the component configuration.

Usage

Once the extension is configured, simply use it in your views by:

<?php 
    $this->title = 'page title';
    $this->description = 'page description';
    $this->keywords = ['keywords', 'for', 'this', 'page'];
    $this->image = 'http://domain.com/images/page-image.jpg'; 
?>

Proudly made by Daxslab.

]]>
0
[extension] daxslab/yii2-uploader-behavior Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/daxslab/yii2-uploader-behavior https://www.yiiframework.com/extension/daxslab/yii2-uploader-behavior glpzzz glpzzz

Yii2 Uploader Behavior for Active Record

  1. Installation
  2. Usage

Build Status Latest Stable Version Total Downloads Latest Unstable Version License

Automates file uploading for every attribute tagged with file or image validation rule. It also configures the way that filename should be renamed and stored in database as attribute value.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist daxslab/yii2-uploader-behavior "*"

or add

"daxslab/yii2-uploader-behavior": "*"

to the require section of your composer.json file.

Usage

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

use daxslab/behaviors/UploaderBehavior;

public function behaviors() {
    return [
        UploaderBehavior::className()
    ];
}

This is the simplest way of usage. It will look for all attributes with a file or image validation rule.

public function rules()
{
    return [
        [['name'], 'required'],
        [['name'], 'string', 'max' => 256],
        [['image'], 'image', 'skipOnEmpty' => true],
    ];
}

And update the form to specify a file input for the image attribute:

$form->field($model, 'image')->fileInput();

For a more controlled usage, you can specify which attributes to control using the attributes option as in :

use daxslab/behaviors/UploaderBehavior;

public function behaviors() {
    return [
        [
            'class' => UploaderBehavior::className(),
            'attributes' => ['avatar'] // or you can use the string format as in 'attributes' => 'avatar'
        ]
    ];
}

By default the filename of the uploaded file is randomized, but if you want to configure it you can setup the renamer option:

use daxslab/behaviors/UploaderBehavior;

public function behaviors() {
    return [
        [
            'class' => UploaderBehavior::className(),
            'attributes' => ['avatar'] // or you can use the string format as in 'attributes' => 'avatar'
            'renamer' => UploaderBehavior::RENAME_MD5 //will encode the filename with md5()
        ]
    ];
}

also you can specify a custom function to rename the filename:

use daxslab/behaviors/UploaderBehavior;

public function behaviors() {
    return [
        [
            'class' => UploaderBehavior::className(),
            'attributes' => ['avatar'] // or you can use the string format as in 'attributes' => 'avatar'
            'renamer' => function($name, $owner){
                return strtoupper($name); //will turn the filename into uppercase
            }
        ]
    ];
}

Proudly made by Daxslab.

]]>
0
[extension] floor12/yii2-notification Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/floor12/yii2-notification https://www.yiiframework.com/extension/floor12/yii2-notification floor12 floor12

yii2-notification

  1. Installation
  2. Using as JS
  3. Using as PHP

Latest Stable Version Scrutinizer Code Quality Latest Unstable Version Total Downloads License

Этот файл так же доступен на русском языке.

This simple extension helps to show nice notifications in browser. It use svg icons and can be customised by overwriting base CSS styles.

Image

Installation

Just run: `bash $ composer require floor12/yii2-notification or add this to the require section of your composer.json.json "floor12/yii2-notification": "dev-master" `

To include js and css files, add floor12\notification\NotificationAsset as dependency in your AppAsset:

use floor12\notification\NotificationAsset;
use yii\web\AssetBundle;

class AppAsset extends AssetBundle
{
    ...
    public $depends = [
        NotificationAsset::class
    ];
}

Using as JS

To show notification in browser just pass message text to one of the f12notification object methods:

f12notification.info(text);    //information message;
f12notification.success(text); //success message;
f12notification.error(text);   //error message;

For example:

if (userSucces == true)
  f12notification.success('Registration success'.)
else
  f12notification.error('Registration failed.')

Using as PHP

Its also possible to show notifications by passing message text to one of the floor12\notification\Notification methods:

use floor12\notification\Notification;

Notification::info('The form is loading...');
Notification::error('Pleas fill all required fields');
Notification::success('This model is saved');

In case if using PHP api, NotificationAsset will be included in your app by Notification class.

]]>
0
[extension] luc1/yii2-tourist Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/luc1/yii2-tourist https://www.yiiframework.com/extension/luc1/yii2-tourist 1Luc1 1Luc1

Tourist Extension for Yii 2

  1. Installation
  2. Register Asset
  3. Usage

Yii2 extension for the the Tourist component: https://github.com/IGreatlyDislikeJavascript/bootstrap-tourist

The Tourist component is a fork of Bootstrap Tour: https://github.com/sorich87/bootstrap-tour

This extension reuses code from the yii2-bootstrap-tour extension: https://github.com/MyCademy/yii2-bootstrap-tour

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist luc1/yii2-tourist "*"

or add

"luc1/yii2-tourist": "*"

to the require section of your composer.json file.

Register Asset

class AppAsset extends yii\web\AssetBundle
{
    public $depends = [
        // other dependencies
        'luc\tourist\TouristAsset'        
    ];
}

Usage

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

use luc\tourist\Tourist;

<?= Tourist::widget::widget(
    'clientOptions' => [ //Bootstrap Tour Options, see: http://bootstraptour.com/api/
        'steps' => [
            [
                'element' => "#element1",
                'title' => "Step 1",
                'content' => "Content of my step 1",
            ],
            [
                'element' => "#element2",
                'title' => "Step 2",
                'content' => "Content of my step 2",
            ],
        ],
    ]); 
?>
]]>
0
[extension] iiifx-production/yii2-autocomplete-helper Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/iiifx-production/yii2-autocomplete-helper https://www.yiiframework.com/extension/iiifx-production/yii2-autocomplete-helper iiifx iiifx

Yii2 IDE Autocomplete Helper

  1. Installation
  2. Configuration
  3. Using
  4. Advanced customization

Autocompletion generator for custom components in Yii2.

SensioLabsInsight

Latest Version on Packagist Total Downloads Code Coverage Software License

[English documentation] [[Документация на русском](README.RU.md)]

By default in Yii2 not working autocompletion for custom components. IDE sees no added components and this causes inconvenience in operation.

This extension allows you to automatically generate a file with the autocomplete PHPDoc blocks with which the IDE will recognize all of the components in the application configuration.

Installation

Using Composer:

composer require "iiifx-production/yii2-autocomplete-helper"

Configuration

After installation, you need to one-time set up component to work.

For Yii2 Basic, in @app/config/console.php: `php

'bootstrap' => ['log', 'autocomplete'],
'components' => [
    'autocomplete' => [
        'class' => 'iiifx\Yii2\Autocomplete\Component',
    ],
    # ...
]

For Yii2 Advanced, in **@console/config/main.php**:
```php
    'bootstrap' => ['log', 'autocomplete'],
    'components' => [
        'autocomplete' => [
            'class' => 'iiifx\Yii2\Autocomplete\Component',
        ],
        # ...
    ]

Using

To generate autocompletion in the console: `bash php yii ide-components `

Generator automatically detects the type of application, read all configuration files and generate the autocomplete file to the application root. `bash Yii2 IDE auto-completion helper Vitaliy IIIFX Khomenko, 2019

Success: /home/iiifx/Projects/myProject/_ide_components.php ` Important: For IDE did not swear on the two copies of the Yii class must be main Yii class file marked as a text document - example. The main class is located on the way: @vendor/yiisoft/yii2/Yii.php

Advanced customization

Sometimes the structure of the application differs from the standard and the need to change the generator behavior.

The following are examples of possible configuration options.

Changing the name of the component

If you need to change the name of a autocomplete to another, it is quite simple: `php

'bootstrap' => ['log', 'new-component-name'], # <-- new component name
'components' => [
    'new-component-name' => [ # <-- new component name
        'class' => 'iiifx\Yii2\Autocomplete\Component',
    ],
    # ...
]

When the generator run in the console you need to pass the correct component name:
```bash
php yii ide-components --component=new-component-name
Changing environment

By default, a generator start is only possible for YII_ENV = "dev" environment.

You can change the environment: `php

'bootstrap' => ['log', 'autocomplete'],
'components' => [
    'autocomplete' => [
        'class' => 'iiifx\Yii2\Autocomplete\Component',
        'environment' => 'local', # <-- environment
    ],
    # ...
]

### Changing the generator controller

By default, the generator uses a console controller to create autocompletion.

You can replace the default controller, extend it, or add your own implementation:
```php
    'bootstrap' => ['log', 'autocomplete'],
    'components' => [
        'autocomplete' => [
            'class' => 'iiifx\Yii2\Autocomplete\Component',
            'controllerMap' => [
                'ide-components' => 'iiifx\Yii2\Autocomplete\Controller', # <-- default controller
                'my-custom-generator' => 'path\to\your\custom\Controller', # <-- your controller
            ],
        ],
        # ...
    ]

Now you can run your controller: `bash php yii my-custom-generator `

Link to the controller by default: source/Controller.php.

Changing the autocompletion file

By default, autocompletion file will be named _ide_components.php and will be placed in the application root.

You can change the name and location of the file: `php

'bootstrap' => ['log', 'autocomplete'],
'components' => [
    'autocomplete' => [
        'class' => 'iiifx\Yii2\Autocomplete\Component',
        'result' => '@app/new-file-name.php' # <-- name and path
    ],
    # ...
]

The file path must be relative to aliases framework. Example: **@common/../new-file-name.php**.

### Special configuration files

Sometimes you need to manually specify the application configuration files from which you want to generate autocompletion.

In this case, the generator will not seek configuration, the generator immediately uses this list.

For Yii2 Advanced:
```php
    'bootstrap' => ['log', 'autocomplete'],
    'components' => [
        'autocomplete' => [
            'class' => 'iiifx\Yii2\Autocomplete\Component',
            'config' => [
                '@common/config/main.php', # <-- config list
                '@common/config/main-local.php',
                '@console/config/main.php',
                '@console/config/main-local.php',
                '@backend/config/main.php',
                '@backend/config/main-local.php',
                '@frontend/config/main.php',
                '@frontend/config/main-local.php',
            ],
        ],
        # ...
    ]

For Yii2 Basic: `php

'bootstrap' => ['log', 'autocomplete'],
'components' => [
    'autocomplete' => [
        'class' => 'iiifx\Yii2\Autocomplete\Component',
        'config' => [
            '@app/config/console.php', # <-- config list
            '@app/config/web.php',
        ],
    ],
    # ...
]

### Configuration groups

In big projects sometimes need to be able to generate different autocomplete files depending on the stage of development.

You can group configuration files and generate autocompletion only for a specific group.
```php
    'bootstrap' => ['log', 'autocomplete'],
    'components' => [
        'autocomplete' => [
            'class' => 'iiifx\Yii2\Autocomplete\Component',
            'config' => [
                'frontend' => [
                    '@common/config/main.php', # <-- frontend group
                    '@common/config/main-local.php',
                    '@frontend/config/main.php',
                    '@frontend/config/main-local.php',
                ],
                'backend' => [
                    '@common/config/main.php', # <-- backend group
                    '@common/config/main-local.php',
                    '@backend/config/main.php',
                    '@backend/config/main-local.php',
                ],
                'api' => [
                    '@common/config/main.php', # <-- api group
                    '@common/config/main-local.php',
                    '@common/../api/config/main.php',
                    '@common/../api/config/main-local.php',
                ],
            ],
        ],
        # ...
    ]

Now you can generate autocompletion for the desired group: `bash php yii ide-components --config=api `

]]>
0
[extension] solutosoft/yii-multitenant Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/solutosoft/yii-multitenant https://www.yiiframework.com/extension/solutosoft/yii-multitenant leandrogehlen leandrogehlen

Active Record MultiTenant Extension

  1. Installation
  2. Usage

This extension provides support for ActiveRecord MultiTenant.

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

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist solutosoft/yii-multitenant

or add

"solutosoft/yii-multitenant": "*"

Usage

  1. Creates table with tenant_id column:
class m191023_101232_create_post extends Migration
{
    /**
     * {@inheritdoc}
     */
    public function up()
    {
        $this->createTable('post', [
            'id' =>  $this->primaryKey(),
            'title' => $this->string()->notNull(),
            'category_id' => $this->integer(),
            'content' => $this->string()            
            'tenant_id' => $this->integer(),
        ]);
        
        $this->createTable('category', [
            'id' =>  $this->primaryKey(),
            'name' => $this->string()->notNull(),            
            'tenant_id' => $this->integer(),
        ]);
    }
}

  1. Adds TenantInterface to user model:
use solutosoft\multitenant\MultiTenantRecord;

class User extends MultiTenantRecord implements IdentityInterface, TenantInterface    
{
    /**
     * {@inheritdoc}
     */
    public function getTenantId()
    {
        return // logic to determine tenant from current user
    }
    
    /**
     * Finds user by username attribute
     * This is an example where tenant filter is disabled
     */
    public static function findByUsername($username)
    {
        return static::find()->withoutTenant()->where(['username' => $username]);
    }
    
    ...
    
}
  1. Extends models with tenant_id attribute from MultiTenantRecord intead of ActiveRecord:
use solutosoft\multitenant\MultiTenantRecord;

class Post extends MultiTenantRecord
{    
    ...   
}

class Category extends MultiTenantRecord
{    
    ...   
}

Now when you save or execute some query the tenant_id column will be used. Example:

// It's necessary the user will be logged in

$posts = \app\models\Post::find()->where(['category_id' => 1])->all();
// SELECT * FROM `post` WHERE `category_id` = 1 and `tenant_id` = 1;

$category = \app\models\Category([
  'name' => 'framework'
]);
$category->save();
// INSERT INTO `category` (`name`, `tenant_id`) values ('framework', 1);



]]>
0
[news] Yii 2.0.29 Tue, 22 Oct 2019 16:49:03 +0000 https://www.yiiframework.com/news/256/yii-2-0-29 https://www.yiiframework.com/news/256/yii-2-0-29 samdark samdark

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

Version 2.0.29 is a minor release of Yii 2.0. Additionally to fixing minor bugs it adds PostgreSQL 12 support (including partitioned tables) and adjusts dependency injection container syntax to be closer to what is used in Yii 3:

  • Added support for '__construct()' => ['ConstructorArg1', 'ConstructorArg2']
  • Added support for '__class' => SomeClass::class
  • Instance::of() is now allowed in definitions ('SomeInterface' => Instance::of('SomeService')) and $container->get(Instance::of('SomeInterface')
  • Definition could be defined as static call 'SomeInterface' => [SomeFactory::class, 'createMethod']

Current Yii 2 syntax works as it did so it is not necessary to update your configuration.

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

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

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

]]>
0
[news] Debug extension 2.1.10 released Tue, 22 Oct 2019 13:00:36 +0000 https://www.yiiframework.com/news/255/debug-extension-2-1-10-released https://www.yiiframework.com/news/255/debug-extension-2-1-10-released samdark samdark

Debug extension version 2.1.10 was released. It is tweaking Logs panel not to wrap important columns text and to display arrows in less distracting manner.

See the CHANGELOG for details.

]]>
0
[news] Redis extension 2.0.10 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/254/redis-extension-2-0-10-released https://www.yiiframework.com/news/254/redis-extension-2-0-10-released samdark samdark

We are very pleased to announce the release of Redis extension version 2.0.10.

In this version \yii\redis\Connection::$retryInterval was added. It speficifies wait time between retry in microseconds.

See the CHANGELOG for details.

]]>
0
[extension] kekaadrenalin/yii2-imap Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/kekaadrenalin/yii2-imap https://www.yiiframework.com/extension/kekaadrenalin/yii2-imap kekaadrenalin kekaadrenalin

yii2 Imap

Total Downloads

This library is a fork of https://github.com/yiioverflow/yii2-imap

Installation by composer

{
    "require": {
       "kekaadrenalin/yii2-imap": "dev-master"
    }
}

Or

$ composer require kekaadrenalin/yii2-imap "dev-master"

Use as component

Connection details define in component

'components' => [
    ...
    'imap' => [
        'class' => 'kekaadrenalin\imap\Imap',
        'connection' => [
            'imapPath'       => '{imap.gmail.com:993/imap/ssl}INBOX',
            'imapLogin'      => 'username',
            'imapPassword'   => 'password',
            'serverEncoding' => 'encoding', // utf-8 default.
            'attachmentsDir' => '/',
            'decodeMimeStr'  => true, // Return as is, default -> true
        ],
    ],
    ...
 ],

$mailbox = new kekaadrenalin\imap\Mailbox(Yii::$app->imap->connection);

Usage as library

Connection details set on fly

$imapConnection = new kekaadrenalin\imap\ImapConnection;

$imapConnection->imapPath = '{imap.gmail.com:993/imap/ssl}INBOX';
$imapConnection->imapLogin = 'username';
$imapConnection->imapPassword = 'password';
$imapConnection->serverEncoding = 'encoding'; // utf-8 default.
$imapConnection->attachmentsDir = '/';
$imapConnection->decodeMimeStr = true;

$mailbox = new kekaadrenalin\imap\Mailbox($imapConnection);

To get all mails and its index

$mailIds = $mailbox->searchMailBox(); // Gets all Mail ids.
print_r($mailIds);

Do not read attachments

$mailbox->readMailParts = false;

To read Inbox contents

foreach($mailIds as $mailId)
{
    // Returns Mail contents
    $mail = $mailbox->getMail($mailId); 

    // Read mail parts (plain body, html body and attachments
    $mailObject = $mailbox->getMailParts($mail);
    
    // Array with IncomingMail objects
    print_r($mailObject);

    // Returns mail attachements if any or else empty array
    $attachments = $mailObject->getAttachments(); 
    foreach($attachments as $attachment){
        echo ' Attachment:' . $attachment->name . PHP_EOL;
        
        // Delete attachment file
        unlink($attachment->filePath);
    }
}

To Mark and delete mail from IMAP server.

$mailbox->deleteMail($mailId); // Mark a mail to delete
$mailbox->expungeDeletedMails(); // Deletes all marked mails

Contribute

Feel free to contribute. If you have ideas for examples, add them to the repo and send in a pull request.

Appreciate

Don't forget to leave me a "star" if you like it. Enjoy coding!

]]>
0
[extension] kekaadrenalin/yii2-module-recaptcha-v3 Tue, 22 Oct 2019 13:18:55 +0000 https://www.yiiframework.com/extension/kekaadrenalin/yii2-module-recaptcha-v3 https://www.yiiframework.com/extension/kekaadrenalin/yii2-module-recaptcha-v3 kekaadrenalin kekaadrenalin

Total Downloads

Yii2 reCAPTCHA v3

  1. Installation
  2. Usage
  3. For tests

Adds recaptcha-v3 into yii2 project

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist kekaadrenalin/yii2-module-recaptcha-v3 "*"

or add

"kekaadrenalin/yii2-module-recaptcha-v3": "*"

to the require section of your composer.json file.

Usage

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

add this to your components main.php

'components' => [
    ...
    'reCaptcha3' => [
        'class'      => 'kekaadrenalin\recaptcha3\ReCaptcha',
        'site_key'   => 'site_key_###',
        'secret_key' => 'secret_key_###',
    ],

and in your model

acceptance_score the minimum score for this request (0.0 - 1.0) or null

public $reCaptcha;
 
public function rules()
{
 	return [
 		...
 		 [['reCaptcha'], \kekaadrenalin\recaptcha3\ReCaptchaValidator::className(), 'acceptance_score' => 0]
 	];
}
<?= $form->field($model, 'reCaptcha')->widget(\kekaadrenalin\recaptcha3\ReCaptchaWidget::class) ?>

For tests

When use `YII_ENV_TESTinindex-test.phpthen disabled recaptcha's validate:php defined('YII_ENV') or define('YII_ENV', 'test'); `

]]>
0
[extension] vkabachenko/yii2-filepond Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/vkabachenko/yii2-filepond https://www.yiiframework.com/extension/vkabachenko/yii2-filepond vkabachenko vkabachenko

Filepond Yii2 extension

  1. Installation
  2. Usage

This extension allows you to use Filepond upload js library as a widget in yii2 projects.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require  vkabachenko/yii2-filepond

or add

"vkabachenko/yii2-filepond": "dev-master"

to the require section of your composer.json file.

Usage

Add the extension to the module section in your config file

    'modules' => [
       'filepond' => [
           'class' => \vkabachenko\filepond\Module::class
       ]
    ],

After that you can use Filepond library to upload files in your project.

Single file upload without model

Single file upload with model

Multiple files upload without model

Multiple files upload with model

Filepond options

Filepond options described at the documentation can be set by setting instanceOptions or settingsOptions.

This is the preferred way:

    <?= FilepondWidget::widget([
            'name' => 'file',
            'instanceOptions' => [
                'required' => true,
                'maxFiles' => 10,
                ... other options ...
            ]
         ]);
    ?>
Filepond plugins

If you want to add some of filepond plugins to the widget, set the allow plugin option to true. For example, to add file type validation plugin set allowFileSizeValidation:

    <?= FilepondWidget::widget([
            'name' => 'file',
            'instanceOptions' => [
                'allowFileSizeValidation' => true,
                'maxFileSize' => '10M',
                ... other options ...
            ]
         ]);
    ?>
Validation

Only client-side validation is available. This kind of validation is the part of filepond library. You can add file size and file type validation. Example of file type validation:

    <?= FilepondWidget::widget([
            'name' => 'file',
            'instanceOptions' => [
                'allowFileTypeValidation' => true,
                'acceptedFileTypes' => ['image/*']
            ]
                ... other options ...
            ]
         ]);
    ?>
Localization

Original library isn't localized and has only english labels. This widget has russian translations too. To apply the localization you have to set language option in Yii settings or directly in the widget:

    <?= FilepondWidget::widget([
            'name' => 'file',
            'language' => 'ru-RU'
         ]);
    ?>
]]>
0
[news] Yii 2.0.28 Tue, 08 Oct 2019 13:27:59 +0000 https://www.yiiframework.com/news/253/yii-2-0-28 https://www.yiiframework.com/news/253/yii-2-0-28 samdark samdark

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

Version 2.0.28 is a minor release of Yii 2.0. This release includes important security and PHP 7 compatibility fixes.

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

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

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

]]>
0
[news] Bootstrap 4 extension version 2.0.8 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/252/bootstrap-4-extension-version-2-0-8-released https://www.yiiframework.com/news/252/bootstrap-4-extension-version-2-0-8-released samdark samdark

Bootstrap 4 extension version 2.0.8 was released fixing non-functional headerOptions in Tabs.

See CHANGELOG for details.

]]>
0
[news] HTTP client extension 2.0.12 released Tue, 08 Oct 2019 10:15:21 +0000 https://www.yiiframework.com/news/251/http-client-extension-2-0-12-released https://www.yiiframework.com/news/251/http-client-extension-2-0-12-released samdark samdark

We are very pleased to announce the release of HTTP client extension version 2.0.12.

This release adds an ability to get time elapsed from request to response via Request::responseTime().

See the CHANGELOG for details.

]]>
0
[news] MongoDB extension 2.1.8 released Tue, 08 Oct 2019 09:39:48 +0000 https://www.yiiframework.com/news/250/mongodb-extension-2-1-8-released https://www.yiiframework.com/news/250/mongodb-extension-2-1-8-released samdark samdark

We are very pleased to announce the release of MongoDB extension version 2.1.8 that fixes Session component compatibility with Yii 2.0.17+.

]]>
0
[extension] solutosoft/yii-linkmany Fri, 27 Sep 2019 11:10:48 +0000 https://www.yiiframework.com/extension/solutosoft/yii-linkmany https://www.yiiframework.com/extension/solutosoft/yii-linkmany leandrogehlen leandrogehlen

Yii LinkMany

  1. Installation
  2. Usage
  3. Credits

Load, validate and save automatically hasMany relations.

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

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist solutosoft/yii-linkmany

or add

"solutosoft/yii-linkmany": "*"

to the require section of your composer.json.

Usage

This extension provides support for ActiveRecord hasMany relation saving. This support is granted via \solutosoft\linkmany\LinkManyBehavior ActiveRecord behavior. You'll need to attach it to your ActiveRecord class and point the target "has-many" relation for it:

class Post extends ActiveRecord
{
    public function behaviors()
    {
        return [
            'linkManyBehavior' => [
                'class' => LinkManyBehavior::class,
                'relations' => [
                    'tags',
                    'messages' => [
                        'formName'  => 'Post[messages]',
                        'validate' => false,
                        'deleteOnUnlink' => false
                    ]
                ]
            ],
        ];
    }

    public function getMessages()
    {
        return $this->hasMany(Message::class, ['post_id' => 'id']);
    }

    public function getTags()
    {
        return $this->hasMany(Tag::class, ['id' => 'tag_id'])
            ->viaTable('post_tag', ['post_id' => 'id']);
    }
}

Being attached \solutosoft\linkmany\LinkManyBehavior you can load data using the method \solutosoft\linkmany\LinkManyBehavior::fill

use yii\web\Controller;

class PostController extends Controller
{
    public function actionCreate()
    {
        $model = new Post();


        /**
         * $_POST could be something like:
         * [
         *     'tags' => [1,2]
         *     'comments' => [
         *         [
         *             'subject' => 'First comment',
         *             'content' => 'This is de fist comment',
         *         ], [
         *             'subject' => 'Second comment',
         *             'content' => 'This is de second comment',
         *         ]
         *     ]
         * ];
         */
        if ($model->fill(Yii::$app->request->post())) {
            $model->save(); // save the model and relations
            return $this->redirect(['view']);
        }

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

Credits

This Package is inspired by:

I wanted to have a combination of both. Thanks to both authors.

]]>
0
[extension] rsr/yii2-check-deps Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/extension/rsr/yii2-check-deps https://www.yiiframework.com/extension/rsr/yii2-check-deps R.S.R R.S.R

yii2-check-deps

  1. Installation
  2. Usage
  3. Resources

Check for new migrations/dependencies of Yii 2 application when in development mode and apply them if user asked to.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --dev rsr/yii2-check-deps

or add

"rsr/yii2-check-deps" : "*"

to the require-dev section of your composer.json file.

Usage

Add the following to yii2 config/web.php file:

...
if (YII_ENV_DEV) {
    ... 
    $config['bootstrap'][] = 'checkDeps';
    $config['components']['checkDeps'] = [
        'class' => rsr\yii2\checkDeps\CheckDeps::class
    ];
    ...
}
...
return $config;

Resources

]]>
0
[extension] raspina Thu, 26 Sep 2019 08:14:32 +0000 https://www.yiiframework.com/extension/raspina https://www.yiiframework.com/extension/raspina mr.rezaee mr.rezaee

http://raspina-cms.ir/

Powered by Yii2 The Fast, Secure and Professional PHP Framework. Yii is a high-performance PHP framework best for developing Web 2.0 applications.

Open Source Raspina is an free and open source project that is licensed under BSD 3.

Multi Language Allows you easily use english, russian and persian languages. You can add your own language.

Transparent, Reliable and Extensible you can easily develop the functionality of your website.

screenshot-sm-2.jpg

]]>
0
[wiki] Yii v2 snippet guide Sun, 20 Oct 2019 21:00:27 +0000 https://www.yiiframework.com/wiki/2552/yii-v2-snippet-guide https://www.yiiframework.com/wiki/2552/yii-v2-snippet-guide rackycz rackycz
  1. Intro
  2. Prerequisities
  3. Yii demo app + GitLab
  4. User management + DB creation + login via DB
  5. i18n translations
  6. Switching languages + session + lang-dropdown in the top menu
  7. Simple access rights
  8. Nice URLs
  9. How to redirect web to subfolder /web
  10. Auto redirection from login to desired URL
  11. What to change when exporting to the Internet
  12. Saving contact inqueries into DB
  13. Tests - unit + opa
  14. Adding a google-like calendar
  15. Scenarios - UNKNOWN SCENARIO EXCEPTION
  16. Richtext / wysiwyg HTML editor - Summernote
  17. SEO optimization
  18. Other useful links

Intro

Hi all!

Please note, that this article will be updated regularly as I have more and more snippets so come back in a few weeks

This snippet guide works with the basic Yii demo application and enhances it. It continues in my series of simple Yii tutorials. Previous two contain basic info about MVC concept, exporting to Excel and other topics so read them as well, but they are meant for Yii v1. I started with them cca in year 2011:

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

I was suprised that the Yii 2 demo application does not contain some basic functionalities (like login via DB, translations etc) which must be implemented in the most of web projects so I will focus on them. Plus I will talk about GitLab.

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

Prerequisities

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

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

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

  • C:\xampp\htdocs

And your index.php should be here:

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

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

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

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

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

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

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

Yii demo app + GitLab

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

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

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

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

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

Automatical copying from GitLab to FTP

I found these two pages where things are explained: link link and I just copied something.

You only need to create 1 file in your GitLab repository. It is named .gitlab-ci.yml and it should contain following code:

variables:
  HOST: "ftp url"
  USERNAME: "user"
  PASSWORD: "password"
  TARGETFOLDER: "relative path if needed, or just ./"

deploy:
  script:
    - apt-get update -qq && apt-get install -y -qq lftp
    - lftp -c "set ftp:ssl-allow no; open -u $USERNAME,$PASSWORD $HOST; mirror -Rnev ./ $TARGETFOLDER --ignore-time --parallel=10 --exclude-glob .git* --exclude .git/ --exclude vendor --exclude web/assets --exclude web/index.php --exclude web/index-test.php" 
  only:
    - master

I just added some exclusions (listed below) and will probably add --delete in the future. Read linked webs.

  • exclude vendor = huge folder with 3rd party SW which is not in GIT
  • exclude web/assets = also some cache
  • exclude web/index.php = in GIT is your devel index with DEBUG mode enabled. You dont wanna have this file in productive environment
  • exclude web/index-test.php = tests are only on your computer and in GIT

User management + DB creation + login via DB

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

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

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

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

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

Then replace existing model User with following snippet

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

namespace app\models;

use Yii;

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

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

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

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

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

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

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

    // ----- Password validator

    public function setPasswordWhenChanged($attribute_name, $params) {

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

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

        return true;
    }

    // ----- IdentityInterface methods:

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

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

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

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

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

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

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

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

}

Validators vs JavaScript:

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

Now you can also create CRUD for the User model using GII:

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

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

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

Open folder views\user and do following:

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

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

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

i18n translations

Translations are fairly simple, but I probably didnt read manuals carefully so it took me some time. Note that now I am only describing translations which are saved in files. I do not use DB translations yet. Maybe later.

1 - Translating short texts and captions

First create following folders and file.

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

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

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

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

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

        // ... other configurations

    ], // end of 'components'
    

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

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

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

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

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

Therefore open the file and paste there following code:

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

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

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

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

2 - Translating long texts and whole views

If you have a view with long texts and you want to translate it into a 2nd language, it is not good idea to use the previous approach, because it uses the English text as the ID.

It is better to translate the whole view. How? ... Just create a sub-folder next to the view and give it name which will be identical to the target-lang-ID. In my case the 2nd language is Czech so I created following folder and copied my view in it. So now I have 2 identical views with identical names:

  • "C:\xampp\htdocs\basic\views\site\about.php" ... English
  • "C:\xampp\htdocs\basic\views\site\cs-CZ\about.php" ... Czech

Yii will automatically use the Czech version if needed.

Switching languages + session + lang-dropdown in the top menu

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

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

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

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

And above the Nav::widget add few rows:

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

and then add one item into Nav::widge

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

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

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

The setLang action looks like this:

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

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

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

    public function beforeAction($action) {

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

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

        return true;
    }

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

<?php

namespace app\controllers;

use Yii;
use yii\web\Controller;

class BaseController extends Controller {

    public function beforeAction($action) {

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

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

        return true;
    }

}

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

Simple access rights

Every controller can allow different users/guests to use different actions. Method behaviors() can be used to do this. If you generate the controller using GII the method will be present and you will just add the "access-part" like this:


// don't forget to add this import:
use yii\filters\AccessControl;

public function behaviors() {
  return [
    // ...
    'access' => [
      'class' => AccessControl::className(),
      'rules' => [
        [
          'allow' => true,
          'roles' => ['@'], // logged in users
          // 'roles' => ['?'], // guests
          // 'matchCallback' => function ($rule, $action) {
            // all logged in users are redirected to some other page
            // just for demonstration of matchCallback
            // return $this->redirect('index.php?r=user/create');
          // }
        ],
      ],
      // All guests are redirected to site/index in current controller:
      'denyCallback' => function($rule, $action) {
        Yii::$app->response->redirect(['site/index']);
      },
    ],
  ];
}

.. This is all I needed so far. I will add more complex snippet as soon as I need it ...

Details can be found here https://www.yiiframework.com/doc/guide/2.0/en/security-authorization.

Nice URLs

Just uncomment section "urlManager" in config/web.php .. htaccess file is already included in the basic demo. In case of problems see this link.

My problem was that images were not displayed when I enabled nice URLs. Smilar discussion here.

// Originally I used these img-paths:
<img src="..\web\imgs\myimg01.jpg"/>

/// Then I had to chage them to this:
Html::img(Yii::$app->request->baseUrl . '/imgs/myimg01.jpg')

// The important change is using the "baseUrl"

Note that Yii::$app->request->baseUrl returns "/myProject/web". No trailing slash.

How to redirect web to subfolder /web

Note: If you are using the advanced demo app, this link can be interesting for you.

Yii 2 has the speciality that index.php is hidden in the web folder. I didnt find in the official documentation the important info - how to hide the folder, because user is not interested in it ...

Our demo application is placed in folder:

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

Now you will need 2 files named .htaccess

  • C:\xampp\htdocs\basic\web\.htaccess
  • C:\xampp\htdocs\basic\.htaccess

The first one is mentioned in chapter Nice URLs and looks like this:

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]

The second is simpler:

RewriteEngine on
RewriteRule ^(.*)$ web/$1 [L]

... it only adds the word "web" into all URLs. But first we have to remove the word from URLs. Open file config/web.php and find section request. Add attribute baseUrl:

'request' => [
  // 'cookieValidationKey' => ...
  'baseUrl' => '/basic', // add this line
],

Now things will work for you. But it might be needed to use different value for devel and productive environment. Productive web is usually in the root-folder so baseUrl should be en empty string. I did it like this:

$baseUrlWithoutWebFolder = "";
if (YII_ENV_DEV) {
  $baseUrlWithoutWebFolder = '/basic';
}

// ...

'request' => [
  // 'cookieValidationKey' => ...
  'baseUrl' => $baseUrlWithoutWebFolder,
],

I will test this and if I find problems and solutions I will add them.

Auto redirection from login to desired URL

... to be added ...

What to change when exporting to the Internet

  • Delete file web/index-test.php
  • In file web/index.php comment you 2 first lines containing YII_DEBUG + YII_ENV
  • Delete the text from view site/login which says "You may login with admin/admin or demo/demo."

Saving contact inqueries into DB

DROP TABLE IF EXISTS `contact` ;

CREATE TABLE IF NOT EXISTS `contact` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NOT NULL,
  `email` VARCHAR(45) NOT NULL,
  `subject` VARCHAR(100) NOT NULL,
  `body` TEXT NOT NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB;
  • Create the DB table
  • Generate Model + CRUD using GII
  • In Site controller replace ContactForm with Contact (in section "use" and in actionContact) and in the action change the IF condition:
    use app\models\Contact;
    // ... 
    public function actionContact() {
      $model = new Contact();
      if ($model->load(Yii::$app->request->post()) && $model->save()) {
      // ...
    
  • Open the new contact model and add one attribute and 2 rules:
public $verifyCode;
// ...
  ['verifyCode', 'captcha'],
  ['email', 'email'],

// and translation for Captcha
'verifyCode' => Yii::t('app', 'Verification'),
  • You can also delete one paragraph from view/site/contact
    <p>
    Note that if you turn on the Yii debugger ...
    

Then some security - filtering users in the new ContactController:

public function beforeAction($action) {

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

  $guestAllowedActions = [];

  if (Yii::$app->user->isGuest) {
    if (!in_array($action->actionMethod, $guestAllowedActions)) {
      return $this->redirect(['site/index']);
    }
  }
  
  return true;
}

Tests - unit + opa

... text ...

Adding a google-like calendar

I needed to show user a list of his events in a large calendar so I used library fullcalendar.

Great demo which you can just copy and paste:

/*I added this style to hide vertical scroll-bars*/
.fc-scroller.fc-day-grid-container{
  overflow: hidden !important;
}
  • Don't forget to use these files for example in your view like this:
$this->registerCssFile('@web/css/fullcalendar/fullcalendar.css');
$this->registerCssFile('@web/css/fullcalendar/fullcalendar.print.css', ['media' => 'print']); 

$this->registerJsFile('@web/js/fullcalendar/moment.min.js', ['depends' => ['yii\web\JqueryAsset']]);
$this->registerJsFile('@web/js/fullcalendar/fullcalendar.min.js', ['depends' => ['yii\web\JqueryAsset']]);

// details here:
// https://www.yiiframework.com/doc/api/2.0/yii-web-view

... if you want to go pro, use NPM. The NPM way is described here.

API is here: https://fullcalendar.io/docs ... you can then enhace the calendar config from the example above

In order to make things work I had to force jQuery to be loaded before calendar scripts using file config/web.php like this

   'components' => [
        
		// ...
		
       'assetManager' => [
            'bundles' => [
                'yii\web\JqueryAsset' => [
                    'jsOptions' => [ 'position' => \yii\web\View::POS_HEAD ],
                ],
            ],
        ],

You can customize the calendar in many ways. For example different event-color is shown here. Check the source code.

Scenarios - UNKNOWN SCENARIO EXCEPTION

I have been using scenarios a lot but today I spent 1 hour on a problem - I had 2 scenarios and one of them was just assigned to the model ...

$model->scenario = "abc";

... but had no rule defined yet. I wanted to implement the rule later, but I didnt know that when you set a scenario to your model it must be used in method rules() or defined in method scenarios(). So take this into consideration. I expected that when the scenario has no rules it will just be skipped or deleted.

Richtext / wysiwyg HTML editor - Summernote

If you want to allow user to enter html-formatted text, you need to use some HTML wysiwyg editor, because ordinary TextArea can only work with plain text. It seems to me that Summernote is the simplest addon available:

// Add following code to file layouts/main.php .. 
// But make sure jquery is already loaded !! 
// - Read about this topic in chapter "Adding a google-like calendar"

<!-- include summernote css/js -->
<link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.css" rel="stylesheet">
<script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.js"></script>

// And then in any view you can use this code:

<script>
$(document).ready(function() {
  $('#summernote1').summernote();
  $('#summernote2').summernote();
});
</script>
<div id="summernote1">Hello Summernote</div>

<form method="post">
  <textarea id="summernote2" name="editordata"></textarea>
</form>

On this page I showed how to save Contacts inqueries into database. If you want to use the richtext editor in this section, open view contact/_form.php and just add this JS code:

<script>
$(document).ready(function() {
  $('#contact-body').summernote();
});
</script>

It will be saved to DB as HTML code. But this might be also a source of problems, because user can inject some dangerous HTML code. So keep this in mind.

Now you will also have to modify view contact/view.php like this in order to see nice formatted text:

DetailView::widget([
  'model' => $model,
  'attributes' => [
    // ...
    'body:html',
  ],
])

... to discover all possible formatters, check all asXXX() functions on this page:

SEO optimization

This is not really a YII topic but as my article is some kind of a code-library I will paste it here as well. To test your SEO score you can use special webs. For example seotesteronline, but only once per day. It will show some statistics and recommend enhancements so that your web is nicely shown on FB and Twitter or found by Google.

Important are for example OG meta tags or TWITTER meta tags. They are basicly the same. Read more here. You can test them at iframely.com.

Basic tags are following and you should place them to head:

  • Note that Twitter is using attribute "name" instead of "property" which is defined in OG
  • btw OG was introduced by Facebook. Twitter can process it as well, but SEO optimizers will report an error when Twitter's tags are missing.

<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>">
<head>

  <meta property="og:site_name" content="European Travel, Inc.">
  <meta property="og:title" content="European Travel Destinations">
  <meta property="og:description" content="Offering tour packages for individuals or groups.">
  <meta property="og:image" content="http://euro-travel-example.com/thumbnail.jpg">
  <meta property="og:url" content="http://euro-travel-example.com/index.htm">
  <meta name="twitter:card" content="summary_large_image">

  <!--  Non-Essential, But Recommended -->
  <meta property="og:site_name" content="European Travel, Inc.">
  <meta name="twitter:image:alt" content="Alt text for image">

  <!--  Non-Essential, But Required for Analytics -->
  <meta property="fb:app_id" content="your_app_id" />
  <meta name="twitter:site" content="@website-username">
  
  <!-- seotesteronline.com will also want you to add these: -->
  <meta name="description" content="blah blah">
  <meta property="og:type" content="website">
  <meta name="twitter:title" content="blah blah">
  <meta name="twitter:description" content="blah blah">
  <meta name="twitter:image" content="http://something.jpg">

Do not forget about file robots.txt and sitemap.xml:

// robots.txt can contain this:
User-agent: *
Allow: /

Sitemap: http://www.example.com/sitemap.xml
// And file sitemap.xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
  <url>
    <loc>http://example.com/someFile.html</loc>
    <image:image>
      <image:loc>http://example.com/someImg.jpg</image:loc>
    </image:image>
  </url> 
</urlset> 

You can also minify here or here all your files. Adding "microdata" can help as well, but I have never used it. On the other hand what I do is that I compress images using these two sites tinyjpg.com and tinypng.com.

Other useful links

]]>
0
[news] Yii 2.0.27 Wed, 18 Sep 2019 19:15:22 +0000 https://www.yiiframework.com/news/249/yii-2-0-27 https://www.yiiframework.com/news/249/yii-2-0-27 samdark samdark

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

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

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

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

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

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

]]>
0
[news] Debug extension 2.1.9 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/248/debug-extension-2-1-9-released https://www.yiiframework.com/news/248/debug-extension-2-1-9-released samdark samdark

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

See the CHANGELOG for details.

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

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

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

ALTER SESSION SET NLS_DATE_FORMAT = ...

Add this script inside your database connection file

<?php

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

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

    'on afterOpen' => function($event) {
        // $event->sender refers to the DB connection
        $event->sender->createCommand("ALTER SESSION SET NLS_DATE_FORMAT='DD-MM-YYYY hh24:mi:ss'")->execute();
    }    
];
]]>
0
[news] Yii 2.0.26 Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/247/yii-2-0-26 https://www.yiiframework.com/news/247/yii-2-0-26 samdark samdark

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

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

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

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

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

]]>
0
[news] Debug extension 2.1.8 released Thu, 21 Nov 2019 13:09:05 +0000 https://www.yiiframework.com/news/245/debug-extension-2-1-8-released https://www.yiiframework.com/news/245/debug-extension-2-1-8-released samdark samdark

Debug extension version 2.1.8 was released.

This version fixes two bugs:

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

See the CHANGELOG for details.

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

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

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

Let's start with the basic applicaiton template.

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

And config/console.php:

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

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

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

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

Requirements :

  • Yii2 framework advanced template
  • Yii2 nested sets package

Install the package using composer

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

$ composer require creocoder/yii2-nested-sets

Create the table

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

$ ./yii migrate/create create_category_table

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

<?php

use yii\db\Migration;

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

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

Then, generate the table using the migration tool.

$ ./yii migrate

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

Generate the default CRUD using Gii

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

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

Modify models, controllers, and views

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

<?php

namespace common\models;

use Yii;
use creocoder\nestedsets\NestedSetsBehavior;

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

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

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

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

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

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

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

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

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

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

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

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

        return $return;
    }
}

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

use creocoder\nestedsets\NestedSetsBehavior;

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

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

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

<?php

namespace backend\controllers;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

<?php

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

use common\models\Category;

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

<div class="category-form">

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

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

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

    </div>

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

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

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

</div>

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

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

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

Register an event handler at Object-Level

e.g inside the init method of a Model

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

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

Register an event handler at Class-Level

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

So, you can put the registration code as

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

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

see docs

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

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

Understanding Yii 3

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

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

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

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

Introduction

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

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

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

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

Changes overview

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

Source code splitting

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

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

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

Autoloading

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

PSR compatibility

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

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

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

This can often lead to:

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

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

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

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

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

Dependencies injection

[TODO]

Yii 3 composer packages

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

Let's introduce them briefly:

The Framework

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

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

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

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

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

Drivers for yiisoft/db

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

Extensions

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

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

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

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

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

Running your first Yii 3 powered application

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

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

Here's the created structure:

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

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

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

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

Installing the web starter

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

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

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

composer require "foxy/foxy:^1.0.0"

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

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

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

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

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

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

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

Exploring yiisoft/yii-base-web structure:

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

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

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

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

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

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

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

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

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

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

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

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

<?php

namespace app\models;

use app\models\Country;

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

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

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

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

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

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

}

The code for the controller action is the following:

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

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

<?php

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

batch_send1.gif

...looks cool, isn't it?

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

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

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

So we create models/Identity.php:

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

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

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

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

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

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

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


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

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

        if (!$model) {
            return false;
        }

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

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

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

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

        if (!$model) {
            return false;
        }

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

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

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

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

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

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

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

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

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

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

        return $this->_user;
    }
}

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

]]>
0
[wiki] Update and Delete buttons on Breadcrumb Thu, 21 Nov 2019 13:09:05 +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 Thu, 21 Nov 2019 13:09:05 +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 Tue, 08 Oct 2019 13:54:13 +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

Agência Next4 Comunicação Digital Ltda.

]]>
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