Live News for Yii Framework News, fresh extensions and wiki articles about Yii framework. Wed, 23 Jan 2019 17:41:45 +0000 Zend_Feed_Writer 2 (http://framework.zend.com) https://www.yiiframework.com/ [extension] alcea/yii2-prism-syntax-highlighter Wed, 23 Jan 2019 17:41:44 +0000 https://www.yiiframework.com/extension/alcea/yii2-prism-syntax-highlighter https://www.yiiframework.com/extension/alcea/yii2-prism-syntax-highlighter necaz necaz

Latest Stable Version Total Downloads Latest Unstable Version License

YII2 Prism Syntax Highlighter

Prism is a lightweight, extensible syntax highlighter, built with modern web standards in mind. It’s used in thousands of websites, including some of those you visit daily.

How to install?

1. Use composer
composer require alcea/yii2-prism-syntax-highlighter "~1"
2. or, edit require section from composer.json
"alcea/yii2-prism-syntax-highlighter": "~1"
3. or, clone from GitHub
git clone https://github.com/alceanicu/yii2-prism-syntax-highlighter

How to use?

<?php

use alcea\yii2PrismSyntaxHighlighter\PrismSyntaxHighlighter;
 
PrismSyntaxHighlighter::widget([
    'theme' => PrismSyntaxHighlighter::THEME_DEFAULT,
    'languages' => ['php', 'php-extras', 'css'],
    'plugins' => ['copy-to-clipboard']
]);

$md = <<<MD_FILE
'''js
$(document).on('focusout', 'input[name="test"]', function(event) {
	event.preventDefault();
	// do ...
});
'''
MD_FILE;

echo Markdown::process($md, 'gfm-comment');
PrismJs page http://prismjs.com/download.html
]]>
0
[extension] yetopen/yii2-usuario-ldap Wed, 23 Jan 2019 17:41:44 +0000 https://www.yiiframework.com/extension/yetopen/yii2-usuario-ldap https://www.yiiframework.com/extension/yetopen/yii2-usuario-ldap maxxer maxxer

Yii2 Usuario LDAP

  1. Installation
  2. Configuration

An yii2 extension to authenticate and/or syncronize users against LDAP for 2amigos/yii2-usuario.

Installation

The preferred way to install this extension is through composer.

Either run:

php composer.phar require --prefer-dist yetopen/yii2-usuario-ldap "*"

or add

"yetopen/yii2-usuario-ldap": "*"

to the require section of your composer.json file.

Configuration

Add in your config (config/web.php for the basic app):

//...
'bootstrap' => ['log', 'usuarioLdap'],
//...
'components' => [
    //...
    'usuarioLdap' => [
        'class' => 'yetopen\usuarioLdap\Module',
        'ldapConfig' => [
            'hosts' => ['host.example.com'],
            'base_dn' => 'dc=mydomain,dc=local',
            'account_prefix' => 'cn=',
            'account_suffix' => ',ou=Users,dc=mydomain,dc=local',
            'use_ssl' => true,
            'username' => 'bind_username',
            'password' => 'bind_password',
        ],
        'createLocalUsers' => TRUE,
        'defaultRoles' => ['standardUser'],
        'syncUsersToLdap' => TRUE,
        'secondLdapConfig' => [
            'hosts' => ['host.example.com'],
            'base_dn' => 'dc=mydomain,dc=local',
            'account_prefix' => 'cn=',
            'account_suffix' => ',ou=Users,dc=mydomain,dc=local',
            'username' => 'bind_username',
            'password' => 'bind_password',
        ],
    ],
    //...
]

adapting parameters to your setup.

Configuration options
  • ldapConfig: all the parameters for connecting to LDAP server as documented in Adldap2
  • createLocalUsers: if TRUE when a user successfully authenticate against the first LDAP server is created locally in Yii database. If FALSE a default users with ID specified in defaultUserId is used for the session
  • defaultRoles: if specified the role/s will be assigned to the users created by the extension. Can be set as an array. Default to FALSE
  • secondLdapConfig: if specified this is used as LDAP server for sync the local users, if not specified this is equal to ldapConfig
  • syncUsersToLdap: if TRUE changes to local users are synchronized to the second LDAP server. This includes creation and deletion of an user
  • defaultUserId: if createLocalUsers is set to FALSE must contain the ID of an user to be used as local. Defaults to -1
]]>
0
[extension] aryelds/yii2-sweet-alert Wed, 23 Jan 2019 17:41:44 +0000 https://www.yiiframework.com/extension/aryelds/yii2-sweet-alert https://www.yiiframework.com/extension/aryelds/yii2-sweet-alert Aryel Santos Aryel Santos

yii2-sweet-alert

  1. Installation
  2. Usage
  3. For more options visit the plugin page
  4. License

Simple way to flash sweet alert messages to the screen. This widget is a wrapper by SweetAlert Plugin

Installation

The preferred way to install this extension is through composer.

To install, either run

$ php composer.phar require aryelds/yii2-sweet-alert "@dev"

or add

"aryelds/yii2-sweet-alert": "@dev"

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

Usage

Basic Message
use aryelds\sweetalert\SweetAlert;

echo SweetAlert::widget([
    'options' => [
        'title' => "Here's a message!"
    ]
]);
A title with a text under
use aryelds\sweetalert\SweetAlert;

echo SweetAlert::widget([
    'options' => [
        'title' => "Here's a message!",
        'text' => "It's pretty, isn't it?"
    ]
]);
Success message
use aryelds\sweetalert\SweetAlert;

echo SweetAlert::widget([
    'options' => [
        'title' => "Good Job!",
        'text' => "You clicked the button!",
        'type' => SweetAlert::TYPE_SUCCESS
    ]
]);

Error message
use aryelds\sweetalert\SweetAlert;

echo SweetAlert::widget([
    'options' => [
        'title' => "Error!",
        'text' => "An error happened!",
        'type' => SweetAlert::TYPE_ERROR
    ]
]);

A warning with "confirm" and "cancel" function
use aryelds\sweetalert\SweetAlert;

echo SweetAlert::widget([
    'options' => [
        'title' => "Are you sure?",
        'text' => "You will not be able to recover this imaginary file!",
        'type' => SweetAlert::TYPE_WARNING,
        'showCancelButton' => true,
        'confirmButtonColor' => "#DD6B55",
        'confirmButtonText' => "Yes, delete it!",
        'cancelButtonText' => "No, cancel plx!",
        'closeOnConfirm' => false,
        'closeOnCancel' => false
    ],
    'callbackJs' => new \yii\web\JsExpression(' function(isConfirm) {
        if (isConfirm) { 
            swal("Deleted!", "Your imaginary file has been deleted.", "success");
        } else { 
            swal("Cancelled", "Your imaginary file is safe :)", "error");
        }
    }')
]);

A replacement for the "prompt" function
use aryelds\sweetalert\SweetAlert;

echo SweetAlert::widget([
    'options' => [
        'title' => "An input!",
        'text' => "Write something interesting:",
        'type' => SweetAlert::TYPE_INPUT,
        'showCancelButton' => true,
        'closeOnConfirm' => false,
        'animation' => "slide-from-top",
        'inputPlaceholder' => "Write something"
    ],
    'callbackJs' => new \yii\web\JsExpression(' function(inputValue) {
        if (inputValue === false) return false;
        if (inputValue === "") { 
            swal.showInputError("You need to write something!");
            return false
        }
        swal("Nice!", "You wrote: " + inputValue, "success");
    }')
]);

Html Message
use aryelds\sweetalert\SweetAlert;
use yii\bootstrap\Html;

echo SweetAlert::widget([
    'options' => [
        'title' => Html::tag('small', 'HTML Message!', ['style' => 'color: #00008B']),
        'text' => Html::tag('h2', 'Custom Message'),
        'type' => SweetAlert::TYPE_INFO,
        'html' => true
    ]
]);

Using SweetAlert with flash messages
Controller Example
public function actionPage() {
    $model = new SomeModel();
    
    Yii::$app->getSession()->setFlash('success', [
        'text' => 'My custom text',
        'title' => 'My custom title',
        'type' => 'success',
        'timer' => 3000,
        'showConfirmButton' => false
    ]);

    return $this->render('page', [
        'model' => $model,
    ]);
}
The View
use aryelds\sweetalert\SweetAlert;

foreach (Yii::$app->session->getAllFlashes() as $message) {
    echo SweetAlert::widget([
        'options' => [
            'title' => (!empty($message['title'])) ? Html::encode($message['title']) : 'Title Not Set!',
            'text' => (!empty($message['text'])) ? Html::encode($message['text']) : 'Text Not Set!',
            'type' => (!empty($message['type'])) ? $message['type'] : SweetAlert::TYPE_INFO,
            'timer' => (!empty($message['timer'])) ? $message['timer'] : 4000,
            'showConfirmButton' =>  (!empty($message['showConfirmButton'])) ? $message['showConfirmButton'] : true
        ]
    ]);
}
Using themes
You can select one of the following options:
SweetAlert::THEME_TWITTER
SweetAlert::THEME_GOOGLE
SweetAlert::THEME_FACEBOOK
Example:
use aryelds\sweetalert\SweetAlert;

echo SweetAlert::widget([
    'options' => [
        'title' => 'Themes!',
        'text' => 'Here\'s the Twitter theme for SweetAlert!',
        'confirmButtonText' => "Cool!",
        'animation' => 'slide-from-top',
        'theme' => SweetAlert::THEME_TWITTER
    ]
]);

For more options visit the plugin page

SweetAlert

License

yii2-sweet-alert is released under the BSD 3-Clause License. See the bundled LICENSE.md for details.

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

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

This version bumps psy/psysh dependency to ~0.9.3.

]]>
0
[extension] yii2-casbin Mon, 07 Jan 2019 14:03:35 +0000 https://www.yiiframework.com/extension/yii2-casbin https://www.yiiframework.com/extension/yii2-casbin techoner techoner

Yii-Casbin

  1. Installation
  2. Usage
  3. Define your own model.conf
  4. Learning Casbin

Use Casbin in Yii 2.0 PHP Framework.

Installation

Getting Composer package

Require this package in the composer.json of your Yii 2.0 project. This will download the package.

composer require casbin/yii-adapter
Configuring application

To use this extension, you have to configure the Casbin class in your application configuration:

return [
    //....
    'components' => [
        'casbin' => [
            'class' => '\CasbinAdapter\Yii\Casbin',
            
            /*
             * Yii-casbin model setting.
             */
            'model' => [
                // Available Settings: "file", "text"
                'config_type' => 'file',
                'config_file_path' => '/path/to/casbin-model.conf',
                'config_text' => '',
            ],

            // Yii-casbin adapter .
            'adapter' => '\CasbinAdapter\Yii\Adapter',

            /*
             * Yii-casbin database setting.
             */
            'database' => [
                // Database connection for following tables.
                'connection' => '',
                // CasbinRule tables and model.
                'casbin_rules_table' => '{{%casbin_rule}}',
            ],
        ],
    ]
];

Usage

This provides the basic access to Casbin via the casbin application component:


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

$sub = 'alice'; // the user that wants to access a resource.
$obj = 'data1'; // the resource that is going to be accessed.
$act = 'read'; // the operation that the user performs on the resource.

if (true === $casbin->enforce($sub, $obj, $act)) {
    // permit alice to read data1x
} else {
    // deny the request, show an error
}

Define your own model.conf

Supported models.

Learning Casbin

You can find the full documentation of Casbin on the website.

]]>
0
[extension] casbin/yii-adapter Wed, 23 Jan 2019 17:41:44 +0000 https://www.yiiframework.com/extension/casbin/yii-adapter https://www.yiiframework.com/extension/casbin/yii-adapter techoner techoner

Yii-Casbin

  1. Installation
  2. Usage
  3. Define your own model.conf
  4. Learning Casbin

Use Casbin in Yii 2.0 PHP Framework.

Installation

Getting Composer package

Require this package in the composer.json of your Yii 2.0 project. This will download the package.

composer require casbin/yii-adapter
Configuring application

To use this extension, you have to configure the Casbin class in your application configuration:

return [
    //....
    'components' => [
        'casbin' => [
            'class' => '\CasbinAdapter\Yii\Casbin',
            
            /*
             * Yii-casbin model setting.
             */
            'model' => [
                // Available Settings: "file", "text"
                'config_type' => 'file',
                'config_file_path' => '/path/to/casbin-model.conf',
                'config_text' => '',
            ],

            // Yii-casbin adapter .
            'adapter' => '\CasbinAdapter\Yii\Adapter',

            /*
             * Yii-casbin database setting.
             */
            'database' => [
                // Database connection for following tables.
                'connection' => '',
                // CasbinRule tables and model.
                'casbin_rules_table' => '{{%casbin_rule}}',
            ],
        ],
    ]
];

Usage

This provides the basic access to Casbin via the casbin application component:


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

$sub = 'alice'; // the user that wants to access a resource.
$obj = 'data1'; // the resource that is going to be accessed.
$act = 'read'; // the operation that the user performs on the resource.

if (true === $casbin->enforce($sub, $obj, $act)) {
    // permit alice to read data1x
} else {
    // deny the request, show an error
}

Define your own model.conf

Supported models.

Learning Casbin

You can find the full documentation of Casbin on the website.

]]>
0
[extension] rakhmatov/yii2-playmobile Fri, 21 Dec 2018 20:26:40 +0000 https://www.yiiframework.com/extension/rakhmatov/yii2-playmobile https://www.yiiframework.com/extension/rakhmatov/yii2-playmobile rakhmatov rakhmatov

Playmobile

  1. Installation
  2. Usage

Playmobile

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist rakhmatov/yii2-playmobile "*"

or add

"rakhmatov/yii2-playmobile": "*"

to the require section of your composer.json file.

Usage

execute the migration here

yii migrate --migrationPath=@vendor/rakhmatov/yii2-playmobile/src/migrations

add this to components

        'playmobile' => [
            'class' => \rakhmatov\playmobile\components\Connection::class,
            'username' => 'here playmobile login',
            'password' => 'here playmobile password',
        ],

example

`

\Yii::$app->playmobile->sendSms('+998999999999', 'Hello from playmobile')
       

`

]]>
0
[extension] vasadibt/yii2-onesignal Wed, 23 Jan 2019 17:41:44 +0000 https://www.yiiframework.com/extension/vasadibt/yii2-onesignal https://www.yiiframework.com/extension/vasadibt/yii2-onesignal vasadibt vasadibt

Yii2 Onesignal api

  1. Installation
  2. Config
  3. Usage

This is a restful api to onesignal.

Total Downloads Scrutinizer Code Quality

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist vasadibt/yii2-onesignal "dev-master"

or add

"vasadibt/yii2-onesignal": "dev-master"

to the require section of your composer.json file.

Config

Once the extension is installed, you have to configure the api component:

'components' => [
    'onesignal' => [
        'class' => '\vasadibt\onesignal\OneSignal',
        'appId' => 'your-app-id-hash-code',
        'appAuthKey' => 'SetYourAppAuthKey',
        'userAuthKey' => 'SetYourUserAuthKey',
        'enabled' => YII_ENV_PROD ? true : false,
    ],
],

Usage

Call api endpoints:


Yii::$app->onesignal->apps->getAll();

Yii::$app->onesignal->devices->getOne('asd-asd-asd-asd-asd-asd');
Yii::$app->onesignal->devices->getAll();


Yii::$app->onesignal->notifications->add([
    'include_player_ids' => ['player-hash-code-12345-123456789'],
    'contents' => ["en" => 'New message'],
]);


Yii::$app->onesignal->notifications->add([
    'included_segments' => ['All'],
    'contents' => ["en" => 'New message'],
]);
]]>
0
[extension] genxoft/yii2-oas3 Wed, 23 Jan 2019 17:41:44 +0000 https://www.yiiframework.com/extension/genxoft/yii2-oas3 https://www.yiiframework.com/extension/genxoft/yii2-oas3 genxoft genxoft

Open Api Swagger 3 for Yii2 Framework

  1. Requirements
  2. Installation
  3. Integration
  4. Open Api Swagger 3 example annotation
  5. Donate
  6. LICENSE

Requirements

  • PHP 7.1
  • Yii2 Framework

Installation

The preferred way to install this wrapper is through composer.

php composer.phar require genxoft/yii2-oas3 "*"

or

composer require genxoft/yii2-oas3 "*"

or add to the require section of composer.json

"genxoft/yii2-oas3" : "*"

Integration

Add action to web controller (for example SiteController.php):

public function actions()
{
    return [
        'api-docs' => [
            'class' => 'genxoft\swagger\ViewAction',
            'apiJsonUrl' => \yii\helpers\Url::to(['/site/api-json'], true),
        ],
        'api-json' => [
            'class' => 'genxoft\swagger\JsonAction',
            'dirs' => [
                Yii::getAlias('@api/modules/api/controllers'),
                Yii::getAlias('@api/modules/api/models'),
                Yii::getAlias('@api/models'),
            ],
        ],
    ];
}

Open Api Swagger 3 example annotation

Api server description

/**
 * @OA\Info(
 *   version="1.0",
 *   title="Application API",
 *   description="Server - Mobile app API",
 *   @OA\Contact(
 *     name="John Smith",
 *     email="john@example.com",
 *   ),
 * ),
 * @OA\Server(
 *   url="https://example.com/api",
 *   description="main server",
 * )
 * @OA\Server(
 *   url="https://dev.example.com/api",
 *   description="dev server",
 * )
 */
 
class DefaultController extends Controller
{
...

Controller annotation

/**
 * @OA\Get(path="/",
 *   summary="Handshake",
 *   tags={"handshake"},
 *   @OA\Parameter(
 *     name="access-token",
 *     in="header",
 *     required=false,
 *     @OA\Schema(
 *       type="string"
 *     )
 *   ),
 *   @OA\Response(
 *     response=200,
 *     description="Returns Hello object",
 *     @OA\MediaType(
 *         mediaType="application/json",
 *         @OA\Schema(ref="#/components/schemas/Hello"),
 *     ),
 *   ),
 * )
 */
public function actionIndex()
{
... 

Model annotation

/**
 *@OA\Schema(
 *  schema="Hello",
 *  @OA\Property(
 *     property="message",
 *     type="string",
 *     description="Text message"
 *  ),
 *  @OA\Property(
 *     property="time",
 *     type="integer",
 *     description="Server current Unix time"
 *  ),
 *  @OA\Property(
 *     property="date",
 *     type="string",
 *     format="date-time",
 *     description="Server current date time"
 *  )
 *)
 */
class Hello extends Model
{
...

Donate

btn_donateCC_LG.gif

LICENSE

This curl wrapper is released under the MIT license.

]]>
0
[extension] genxoft/curl Wed, 23 Jan 2019 17:41:44 +0000 https://www.yiiframework.com/extension/genxoft/curl https://www.yiiframework.com/extension/genxoft/curl genxoft genxoft

php-curl wrapper

  1. Requirements
  2. Installation
  3. Quick usage
  4. Basic usage
  5. Donate
  6. LICENSE

Simple curl wrapper with REST methods support:

  • GET
  • HEAD
  • POST
  • PUT
  • PATCH
  • DELETE

Requirements

  • PHP 5.4+
  • curl php extension

Installation

The preferred way to install this wrapper is through composer.

php composer.phar require genxoft/curl "*"

or

composer require genxoft/curl "*"

Quick usage

Quick get request
require_once __DIR__ . '/vendor/autoload.php';
use genxoft\curl\Curl;

$result = Curl::QuickGet("http://example.com", ["text_param" => "text_value"]);

You can see also Curl::QuickPost and Curl::QuickJson quick methods

Basic usage

Post request with Json data

Performing post request with Json data and query params

require_once __DIR__ . '/vendor/autoload.php';
use genxoft\curl\Curl;
use genxoft\curl\Request;

$request = new Request("http://example.com");
$request->addGetParam("action", "save")
    ->setJsonBody([
        "name" => "John Smith",
        "age" => 23
    ]);
$curl = new Curl($request);
$response = $curl->post();

if ($response === null) {
    echo $curl->getLastError();
} else {
    if ($response->isSuccess()) {
        echo "Data saved";
    } else {
        echo "HTTP Error: ".$response->getStatusMessage();
    }
}

Donate

btn_donateCC_LG.gif

LICENSE

This curl wrapper is released under the MIT license.

]]>
0
[extension] yii-insert-multi-rows Tue, 18 Dec 2018 00:46:55 +0000 https://www.yiiframework.com/extension/yii-insert-multi-rows https://www.yiiframework.com/extension/yii-insert-multi-rows NabiKAZ NabiKAZ
  1. Requirements
  2. Installation
  3. Usage

Creates and executes an INSERT SQL statement for several rows.

Requirements

Yii 1.1 or above

Installation

For insert multi rows, Put this code in components folder under GeneralRepository.php file name.

Usage

$rows = array(
     array('id' => 1, 'name' => 'John'),
     array('id' => 2, 'name' => 'Mark')
);
GeneralRepository::insertSeveral(User::model()->tableName(), $rows);
]]>
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
[extension] chsergey/yii2-rest-client Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/extension/chsergey/yii2-rest-client https://www.yiiframework.com/extension/chsergey/yii2-rest-client chsergey chsergey

REST Client for Yii 2 (ActiveRecord-like model)

  1. Installation
  2. Usage

Latest Stable Version Total Downloads Latest Unstable Version License Code Climate

This extension provides an interface to work with RESTful API via ActiveRecord-like model in Yii 2.

For HTTP requests thanks to GuzzleHttp

Welcome to PR

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist chsergey/yii2-rest-client:0.1.1

or add

"chsergey/yii2-rest-client": "0.1.1"

to the require section of your composer.json.

Usage

]]>
0
[extension] fl0v/yii2-rollbar Wed, 12 Dec 2018 08:37:44 +0000 https://www.yiiframework.com/extension/fl0v/yii2-rollbar https://www.yiiframework.com/extension/fl0v/yii2-rollbar FlorinV FlorinV

Rollbar for Yii2

  1. Installation
  2. Usage
  3. Payload from your exceptions
  4. Log Target
  5. Rollbar Javascript

This extension is a fork from baibaratsky/yii2-rollbar and eroteev/yii2-rollbar. For Yii 1.x use baibaratsky/yii-rollbar.

Installation

The preferred way to install this extension is through composer.

To install, either run

$ php composer.phar require fl0v/yii2-rollbar

or add

"fl0v/yii2-rollbar": "*"

to the require section of your composer.json file.

Usage

  • Add the component configuration in your global config file:
'components' => [
    'rollbar' => [
        'class' => 'fl0v\yii2\rollbar\RollbarLoader',
        'config' => [
            'environment' => '{your_environment}',
            'access_token' => '{rollber_access_token}',
            // other Rollbar config settings
        ],
    ],
]
  • Add the web error handler configuration in your web config file:
'components' => [
    'errorHandler' => [
        'class' => 'fl0v\yii2\rollbar\handlers\WebErrorHandler',
    ],
],
  • Add the console error handler configuration in your console config file:
'components' => [
    'errorHandler' => [
        'class' => 'fl0v\yii2\rollbar\handlers\ConsoleErrorHandler',
    ],
],

Payload from your exceptions

If you want your exceptions to send some additional data to Rollbar, it is possible by implementing PayloadInterface.

use fl0v\yii2\rollbar\PayloadInterface;
 
class SomeException extends \Exception implements PayloadInterface
{
    public function rollbarPayload()
    {
        return ['foo' => 'bar'];
    }
}

Log Target

You may want to collect your logs produced by Yii::error(), Yii::info(), etc. in Rollbar.

Put the following code in your config:

'components' => [
    'log' => [
        'targets' => [
            [
                'class' => 'fl0v\yii2\rollbar\RollbarTarget',
                'levels' => ['error', 'warning', 'info'], // Log levels you want to appear in Rollbar             
                'categories' => ['application'],
            ],
        ],
    ],
],

Rollbar Javascript

Rollbar offers Javascript debugger aswell, see https://docs.rollbar.com/docs/javascript. To use it in Yii2 there is fl0v\yii2\rollbar\RollbarAsset that you can register in your main template.

RollbarAsset is used independently of the server side component, to configure it use assetManager. For the config part of RollbarAsset checkout Rollbar reference https://docs.rollbar.com/docs/rollbarjs-configuration-reference#section-reference.

'assetManager' => [
    ...
    'bundles' => [
        ....
        'fl0v\yii2\rollbar\RollbarAsset' => [
            // Rollbar configuration
            'config' => [
                'accessToken' => '{token}',
                'payload' => [
                    'environment' => '{environment}',                    
                ],
            ],
            // metrics to add to payload, called when the asset is registered
            'payload' => function () {
                return [
                    'person' => [
                        'id' => \Yii::$app->has('user') ? (string) \Yii::$app->user->id : null,
                        'username' => \Yii::$app->has('user') && ! \Yii::$app->user->isGuest ? \Yii::$app->user->identity->username : null,
                    ],
                    'custom' => [
                        'myData' => 'asd',
                        'key' => uniqid(),
                    ],
                ];
            ],
        ],
    ],
],
]]>
0
[extension] cebe/yii2-lifecycle-behavior Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/extension/cebe/yii2-lifecycle-behavior https://www.yiiframework.com/extension/cebe/yii2-lifecycle-behavior CeBe CeBe

Yii 2 lifecycle behavior

  1. Installation
  2. Usage
  3. Status field validation
  4. Program flow validation
  5. Configuring different validation methods

Define the lifecycle of a model by defining allowed status changes in terms of a state machine.

Latest Stable Version Total Downloads License Build Status

Installation

This is an extension for the Yii 2 PHP framework.

Installation is recommended to be done via composer by running:

composer require cebe/yii2-lifecycle-behavior

Alternatively you can add the following to the require section in your composer.json manually and run composer update afterwards:

"cebe/yii2-lifecycle-behavior": "~2.0.0"

Usage

You can add the behavior to an ActiveRecord class. It does not work with yii\base\Model because it relies on the old-attribute feature which is only available in active record.

You can add the behavior to the model by creating a behaviors() method if there is none yet, or add it to the list of exising behaviors.

The following example shows how to define the allowed status changes:

	public function behaviors()
	{
		return [
			'lifecycle' => [
				'class' => cebe\lifecycle\LifecycleBehavior::class,
				'validStatusChanges' => [
					'draft'     => ['ready', 'delivered'],
					'ready'     => ['draft', 'delivered'],
					'delivered' => ['payed', 'archived'],
					'payed'     => ['archived'],
					'archived'  => [],
				],
			],
		];
	}

The above state transitions can be visualized as the following state machine:

Visualization of state transitions

Status field validation

By default, the behavior will validate the status attribute of the record, when validate() or save() is called and add a validation error in case state has changed in a way that is not allowed.

  • The attribute to validate can be configured by setting the statusAttribute property of the behavior.
  • The error message can be configured by setting the validationErrorMessage property of the behavior. The place holders {old} and {new} are being replaced with the corresponding status values.

Program flow validation

The behavior may also be used to validate status changes in program flow. This is different to user input validation as described above, because program flow will be aborted by an exception in this case. For user input, the recipient of the error message is the user, when status is not changed by the user, the recipient of the error is the developer.

Configuring different validation methods

By default status field is validated both, on validation and on update. To disable one of the methods, you may configure the $events propery, which is by default:

'events' => [
    BaseActiveRecord::EVENT_BEFORE_VALIDATE => 'handleBeforeValidate',
    BaseActiveRecord::EVENT_BEFORE_UPDATE => 'handleBeforeSave',
]
]]>
0
[news] PHP 7.3.0 released Sat, 08 Dec 2018 10:02:10 +0000 https://www.yiiframework.com/news/191/php-7-3-0-released https://www.yiiframework.com/news/191/php-7-3-0-released samdark samdark

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

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

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

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

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

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

SOME_TABLE -> SomeTable
Other_Table -> OtherTable

instead of

SOME_TABLE -> SOMETABLE
Other_Table -> OtherTable

See the CHANGELOG for details.

]]>
0
[extension] widewhale/yii2-debug-vardumper Fri, 07 Dec 2018 12:12:09 +0000 https://www.yiiframework.com/extension/widewhale/yii2-debug-vardumper https://www.yiiframework.com/extension/widewhale/yii2-debug-vardumper widewhale widewhale

VarDumper panel for Yii2-debug

This extensions adds a panel which show var dumps using custom VarDumper::dump($var) function.

Installation

Install extention via composer command: `sh composer require widewhale/yii2-debug-vardumper `

Then add panel to your debug config: `php 'modules'=>[

...
'debug'=>[
    ...
    'panels'=>[
        ...
        'vardumper'=>[
            'class'=>'\widewhale\debug\vardumper\panels\VarDumperPanel'
        ]
    ]
]
...

] `

Usage
...

use widewhale\debug\vardumper\components\VarDumper;

...

VarDumper::dump($var);

Since class name same as yii\helpers\VarDumper you basicly can just replace yii\helpers\VarDumper with widewhale\debug\vardumper\components\VarDumper if you're used default VarDumper helper previously.

IMPORTANT If you want to use yii\helpers\VarDumper and widewhale\debug\vardumper\components\VarDumper simultaneously you should use aliases (or fully qualified namespace names) `php use widewhale\debug\vardumper\components\VarDumper; use yii\helpers\VarDumper as YiiVarDumper;

...

VarDumper::dump($var); YiiVarDumper::dump($var);

OR

\widewhale\debug\vardumper\components\VarDumper::dump($var);

 

]]>
0
[extension] language/yii2-protobuf Sat, 08 Dec 2018 15:07:58 +0000 https://www.yiiframework.com/extension/language/yii2-protobuf https://www.yiiframework.com/extension/language/yii2-protobuf Languege Languege

Yii Protobuf Extension is a wrapper for php protobuf c-extension.It provides an easy way to decode/encoder protobuf data with Yii.In addition to,it provides a tool to generate php proto files from .proto.

You must install php c-ext before you can use this extension

Requirements

To use PHP runtime library requires:

  • C extension:protobuf >= 3.5.0
  • PHP package:php >= 7.0.0
  • Yii2.0 or above
Installation

You can install this extension by composer, as follows: `bash composer require language/yii2-protobuf `

Configure

You need to add protobuf parser/formatter for request/response Component, as follows: `php return [

...
'components' => [
        ...
    'request' => [
        // !!! insert a secret key in the following (if it is empty) - this is required by cookie validation
        'cookieValidationKey' => 'inwyiHVV0KPon5UhGv6l0QYaWL4SC1ww',
        'parsers' => [
            'application/x-protobuf' => 'Language\Protobuf\ProtobufParser'
        ],
    ],
    'response' => [
        'formatters'=>[
            'protobuf' => [
                'class'=>'Language\Protobuf\ProtobufResponseFormatter',
                'hump'=>true, //By default, the field name is underlined to hump, for example, iphone_num is converted to IphoneNum.
            ],
        ],
    ],
    ...
],

]

As you can see, this extension use ```application/x-protobuf``` Content-Type to distinguish protobuf binary data.So, Client should set Content-Type as 
```application/x-protobuf``` when it send protobuf binary data to Server

### Generate Proto
You can run build.sh shell script to generate proto files after Editing msg.proto. it will generate ```PbApp``` and ```GPBMetadata```.You should always edit .proto instead of editing generated proto files
 ```shell
bash build.sh
Register Proto

You need to register .proto.php files for encode protobuf data after generate proto files.You can create a base controller and register them, As follows:

class BaseController extends Controller
{
    use ProtobufTrait;  //Inject using the trait attribute asProtobuf method

    public function init()
    {
        parent::init();
        // 消息文件注册
        ProtobufManager::register(ROOT . '/proto/msg.proto.php');
    }
}

ProtobufTrait provides `asProtobuf` method to convert php hash table to protobuf data

Usage

You should alway get request params with `$request->getBodyParams()`intead of `$_REQUEST`.ProtobufParser parser protobuf to array `php <?php /**

  • Created by PhpStorm.
  • User: liugaoyun
  • Date: 2018/12/1
  • Time: 下午9:10 */

namespace frontend\controllers;

use Language\Protobuf\ProtobufTrait; use yii\base\Controller;

class TestController extends Controller {

public function actionProtobuf(){
    //params
    $params = \Yii::$app->getRequest()->getBodyParams();

    //TODO:your logic

    //convert array to protobuf
    $data = [
        'UserInfo'=>[
            'OpenUid'=>'xxxx',
            'NickName'=>'xxxx',
            'Age'=>100,
            'Param1'=>1000
        ],
        'AddrList'=>[
            'home'=>[
                'Address'=>'addr1',
                'IphoneNum'=>'153xxxx6476'
            ],
            'company'=>[
                'Address'=>'addr2',
                'IphoneNum'=>'188xxxx7049'
            ],
        ],
        'GoneCities'=>[
            ['Name'=>'Beijing'],
            ['Name'=>'Hangzhou'],
        ]
    ];
    return $this->asProtobuf(['class'=>'PbApp\UserLoginACK', 'data'=>$data]);
}

} `

Sample `text

xxxxxxxxd � home 153xxxx6476 company 188xxxx7049 Beijing

Hangzhou `

Customized Request Struct

By default, protobuf parser can only parser map<string,string> protobuf data as message-defined `proto` `protobuf message Request {

map<string,string>  Headers  = 1;			// Header Params
map<string,string>  BodyParams  = 2;         // Body Params

} `

You can define your request proto, as follows `protobuf message Meta{

repeated    Params = 1;

}

message MyRequest {

 map<string,Meta>  Headers  = 1;			// Header Params
    map<string,Meta>  BodyParams  = 2;         // Body Params

} Then, you should tell ProtobufFormatter which class to serialize Array Data php return [

...
'components' => [
        ...
    'response' => [
        'formatters'=>[
            'protobuf' => [
                'class'=>'Language\Protobuf\ProtobufResponseFormatter',
                'hump'=>true, //By default, the field name is underlined to hump, for example, iphone_num is converted to IphoneNum.
                'requestProtoClass'=>'PbApp\MyRequest'
            ],
        ],
    ],
    ...
],

] `

If you need more flexiable data-struct, you can parser the protobuf raw data, as follows: `php message UserMsgLoginREQ{

string  UserName = 1;
string  Password = 2;

}

message FlexiableRequest {

string ProtoClass  = 1;         // proto class to parser
bytes  ProtoData  = 2;         // bytes protobuf data

} `

FlexiableRequest is a internal proto define. So, don't change the message name.

]]>
0
[extension] mailboxvalidator/mailboxvalidator-yii Thu, 06 Dec 2018 00:42:18 +0000 https://www.yiiframework.com/extension/mailboxvalidator/mailboxvalidator-yii https://www.yiiframework.com/extension/mailboxvalidator/mailboxvalidator-yii MailboxValidator MailboxValidator

MailboxValidator Yii Email Validation Extension

  1. Installation
  2. Dependencies
  3. Methods
  4. Usage
  5. Errors
  6. Copyright

MailboxValidator Yii Email Validation Extension provides an easy way to call the MailboxValidator API which validates if an email address is valid.

Installation

Install this extension by using Composer:

`composer require mailboxvalidator/mailboxvalidator-yii`

Dependencies

An API key is required for this module to function.

Go to https://www.mailboxvalidator.com/plans#api to sign up for FREE API plan and you'll be given an API key.

After you get your API key, open your `config/params.php` and add the following line into the array:

'mbvAPIKey' => 'PASTE_YOUR_API_KEY_HERE',

You can also set you API key in controller after calling library. Just do like this:

$mbv = new SingleValidation('PASTE_YOUR_API_KEY_HERE');

or like this:

['email', MailboxValidator::className(), 'option'=>'YOUR_SELECTED_OPTION','api_key'=>'PASTE_YOUR_API_KEY_HERE',],

Methods

Below are the methods supported in this library.

Method Name Description
validateEmail Return the validation result of an email address. Please visit MailboxValidator for the list of the response parameters.
validateFree Check whether the email address is belongs to a free email provider or not. Return Values: True, False
validateDisposable Check whether the email address is belongs to a disposable email provider or not. Return Values: True, False

Usage

Form Validation

To use this library in form validation, first call this library in your model like this:

use MailboxValidator\MailboxValidator;

After that, in the function rules, add the new validator rule for the email:

['YOUR_EMAIL_FIELD_NAME', MailboxValidator::className(), 'option'=>'disposable,free',],

In this line, the extension is been called, and you will need to specify which validator to use. The available validators are disposable and free. After that, refresh you form and see the outcome.

Email Validation

To use this library to get validation result for an email address, firstly load the library in your controller like this:

use MailboxValidator\SingleValidation;

After that, you can get the validation result for the email address like this:

$mbv = new SingleValidation(Yii::$app->params['mbvAPIKey']);
$results = $mbv->FreeEmail('example@example.com');

To pass the result to the view, just simply add the $results to your view loader like this:

return $this->render('YOUR_VIEW_NAME', ['results' => $results]);

And then in your view file, call the validation results. For example:

echo 'email_address = ' . $results->email_address . "<br>";

You can refer the full list of response parameters available at here.

Errors

error_code error_message
100 Missing parameter.
101 API key not found.
102 API key disabled.
103 API key expired.
104 Insufficient credits.
105 Unknown error.

Copyright

Copyright (C) 2018 by MailboxValidator.com, support@mailboxvalidator.com

]]>
0
[extension] panlatent/yii2-odoo Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/extension/panlatent/yii2-odoo https://www.yiiframework.com/extension/panlatent/yii2-odoo panlatent panlatent

logo.svg?sanitize=true

Odoo JSON-RPC Client, Query and ActiveRecord for Yii2


This extension provides the [Odoo](https://www.odoo.com) integration for the [Yii framework 2.0](http://www.yiiframework.com/). It includes [Web Service API](https://www.odoo.com/documentation/10.0/api_integration.html) support and also implements the `Query` and `ActiveRecord` pattern. Documentation is at [Read The Docs](https://yii2-odoo.panlatent.com/). [![Build Status](https://travis-ci.org/panlatent/yii2-odoo.svg)](https://travis-ci.org/panlatent/yii2-odoo) [![Coverage Status](https://coveralls.io/repos/github/panlatent/yii2-odoo/badge.svg)](https://coveralls.io/github/panlatent/yii2-odoo) [![Latest Stable Version](https://poser.pugx.org/panlatent/yii2-odoo/v/stable.svg)](https://packagist.org/packages/panlatent/yii2-odoo) [![Total Downloads](https://poser.pugx.org/panlatent/yii2-odoo/downloads.svg)](https://packagist.org/packages/panlatent/yii2-odoo) [![Latest Unstable Version](https://poser.pugx.org/panlatent/yii2-odoo/v/unstable.svg)](https://packagist.org/packages/panlatent/yii2-odoo) [![License](https://poser.pugx.org/panlatent/yii2-odoo/license.svg)](https://packagist.org/packages/panlatent/yii2-odoo) Requirements ------------ + PHP 7.0 or higher Installation ------------ The preferred way to install this extension is through [composer](http://getcomposer.org/download/). Either run ``` php composer.phar require --prefer-dist panlatent/yii2-odoo "*" ``` or add ``` "panlatent/yii2-odo": "*" ``` to the require section of your `composer.json` file. Usage ----- Once the extension is installed, simply use it in your code by : Add the component to your application. ```php 'components' => [ 'odoo' => [ 'class' => 'panlatent\odoo\Connection', 'dsn' => 'localhost:8000/jsonrpc', 'database' => '', 'username' => '', 'password' => '', ] ] ``` The extension support Yii2 Debug extension: Add the panel component to your application. ```php 'modules' => [ 'debug' => [ 'panels' => [ 'odoo' => [ 'class' => panlatent\odoo\debug\OdooPanel::class, ] ] ] ] ``` The extension support Yii2 Gii extension: Add the panel component to your application. ```php 'modules' => [ 'gii' => [ 'generators' => [ \panlatent\odoo\gii\generators\model\Generator::class, ] ] ] ``` License ------- The Yii2 Odoo is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT).

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

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

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

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

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

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

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

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

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

<?php

namespace app\models;

use app\models\Country;

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

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

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

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

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

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

}

The code for the controller action is the following:

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

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

<?php

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

batch_send1.gif

...looks cool, isn't it?

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

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

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

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

See the CHANGELOG for a full list of changes.

You may discuss this release on the forum.

]]>
0
[extension] matthew-p/yii2-models-select Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/extension/matthew-p/yii2-models-select https://www.yiiframework.com/extension/matthew-p/yii2-models-select MatthewP MatthewP

Select models widget for Yii2

  1. Installation
  2. Usage

Find and select models in select2 input.

Installation

The preferred way to install this extension is through composer.

Either run

php composer.phar require --prefer-dist matthew-p/yii2-models-select "*"

or add

"matthew-p/yii2-models-select": "*"

to the require section of your composer.json file.

Usage

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

$form->field($model, 'attribute')->widget(MPModelSelect::class, [
    'searchModel'     => YouActiveRecordModel::class,
    'valueField'      => 'id',
    'titleField'      => 'title',
    'searchFields'    => [
        // convert to orWhere 'id' => query-string and etc.
        'id', 'title', 
        // add related input (will be added to data request and conver to ->andWhere 'category_id' => request value)
        'category_id' => new JsExpression('$("#category-id").val()'),
        // more examples see MPModelSelect::searchFields
    ],
    'dropdownOptions' => [
        'options'       => [
            'placeholder' => Yii::t('app', 'Select models ...'),
            'multiple'    => true,
        ],
        'pluginOptions' => [
            'minimumInputLength' => 1,
        ],
    ],
])

Add action in controller: `php class SampleController extends Controller { ...

public function actions(): array
{
    return array_merge(parent::actions(), [
        'model-search' => [
            'class' => MPModelSelectAction::class,
        ],
    ]);
}

... } `

Define encryption key in params.php: ` 'MPModelSelect' => [

'encryptionKey' => 'RandomKey',

], `

That's all. Check it.

]]>
0
[extension] devzyj/yii2-rest Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/extension/devzyj/yii2-rest https://www.yiiframework.com/extension/devzyj/yii2-rest devzyj devzyj

REST Extension for Yii2

  1. Installation
  2. Usage
  3. Controllers
  4. UrlRule
  5. Actions
  6. Events
  7. Behaviors

增强 yiisoft/yii2-rest 功能,在 Actions 中增加事件。

并且增加了批量操作的 Actions

Installation

The preferred way to install this extension is through composer.

Either run

composer require --prefer-dist "devzyj/yii2-rest" "~1.0.0"

or add

"devzyj/yii2-rest" : "~1.0.0"

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

Usage

// UserController.php
class UserController extends \devzyj\rest\ActiveController
{
    public $modelClass = 'app\models\User';
    //public $searchModelClass` = 'app\models\UserSearch';
    //public $notFoundMessage = 'User not found: `{id}`';
    //public $allowedCount = 100;
    //public $manyResourcesMessage = 'The number of users requested cannot exceed `{allowedCount}`.';
}

// config.php
return [
    'components' => [
        'urlManager' => [
            ......
            'rules' => [
                [
                    'class' => 'devzyj\rest\UrlRule',
                    'controller' => 'user',
                    //'extraTokens' => ['{account}' => '<account:\\w[\\w]*>'],
                ]
            ]
        ],
    ],
];

调用方法,只列出部分新增的 API:

  • POST /users/validate: 验证创建一个新用户时的数据
  • PATCH /users/123/validate and PUT /users/123/validate: 验证更新用户 123 时的数据
  • POST /users/batch: 创建多个新用户,
  • PATCH /users/batch and PUT /users/batch: 更新多个用户
  • GET /users/10;11;12: 显示用户 10, 11 和 12 的信息
  • DELETE /users/10;11;12: 删除用户 10, 11 和 12

创建多个新用户时的数据格式:

POST /users/batch
    -d [
        {"username": "example1", "email": "user1@example.com"},
        {"username": "example2", "email": "user2@example.com"}
    ]

更新用户 123 和 456 时的数据格式:

PUT /users/batch
    -d {
        "123": {"username": "example1", "email": "user1@example.com"},
        "456": {"username": "example2", "email": "user2@example.com"}
    }

Controllers

  • ActiveController
    • 增加 $searchModelClass 查询数据的模型类名,如果不设置,则使用 $modelClass
    • 增加 $notFoundMessage 模型不存在时的错误信息
    • 增加 $allowedCount 允许批量执行的资源个数
    • 增加 $manyResourcesMessage 批量操作请求资源过多的错误信息
    • 增加 checkActionAccess($action, $params = []) 检查用户是否有执行当前动作的权限
    • 增加 checkModelAccess($model, $action, $params = []) 检查用户是否有执行数据模型的权限
    • 废弃 checkAccess()

UrlRule

  • 增加 $extraTokens 额外的令牌列表。

Actions

修改的 Actions:

  • IndexAction
    • 增加 afterPrepareDataProvider 事件。
  • ViewAction
    • 增加 afterPrepareModel 事件。
  • CreateAction
    • 增加 beforeLoadModel 事件。
    • 增加 afterLoadModel 事件。
    • 增加 beforeProcessModel 事件。
    • 增加 afterProcessModel 事件。
  • UpdateAction
    • 增加 afterPrepareModel 事件。
    • 增加 beforeLoadModel 事件。
    • 增加 afterLoadModel 事件。
    • 增加 beforeProcessModel 事件。
    • 增加 afterProcessModel 事件。
  • DeleteAction
    • 增加 afterPrepareModel 事件。
    • 增加 beforeProcessModel 事件。
    • 增加 afterProcessModel 事件。

增加的 Actions:

  • CreateValidateAction 创建新模型时,验证数据。
    • beforeLoadModel
    • afterLoadModel
    • beforeProcessModel
  • UpdateValidateAction 更新模型时,验证数据。
    • afterPrepareModel
    • beforeLoadModel
    • afterLoadModel
    • beforeProcessModel
  • BatchViewAction 显示多个模型。
    • afterPrepareModel
  • BatchCreateAction 创建多个新模型。
    • beforeLoadModel
    • afterLoadModel
    • beforeProcessModel
    • afterProcessModel
    • afterProcessModels
  • BatchUpdateAction 更新多个模型。
    • afterPrepareModel
    • beforeLoadModel
    • afterLoadModel
    • beforeProcessModel
    • afterProcessModel
    • afterProcessModels
  • BatchDeleteAction 删除多个模型。
    • afterPrepareModel
    • beforeProcessModel
    • afterProcessModel
    • afterProcessModels

Events

  • afterPrepareDataProvider 在准备完数据源后触发的事件。
  • afterPrepareModel 在准备完模型后触发的事件。
  • beforeLoadModel 在模型加载数据前触发的事件,如果返回 false,则阻止模型加载数据。
  • afterLoadModel 在模型成功加载完数据后触发的事件。
  • beforeProcessModel 在处理模型前触发的事件,如果返回 false,则阻止处理模型。
  • afterProcessModel 在成功处理完模型后触发的事件。
  • afterProcessModels 在处理完模型列表后触发的事件。

在批量动作中会多次调用的事件:

  • afterPrepareModel
  • beforeLoadModel
  • afterLoadModel
  • beforeProcessModel
  • afterProcessModel

事件参数说明:

  • 事件参数的类型为 ActionEvent
  • ActionEvent::$object 执行事件时的数据对像,以下列出的是对应事件中的对像类型。
    • afterPrepareDataProvider\yii\data\ActiveDataProvider
    • afterPrepareModel\yii\db\ActiveRecord
    • beforeLoadModelArray
    • afterLoadModel\yii\db\ActiveRecord
    • beforeProcessModel\yii\db\ActiveRecord
    • afterProcessModel\yii\db\ActiveRecord
    • afterProcessModels\devzyj\rest\BatchResult

Behaviors

  • EagerLoadingBehavior 需要手动附加到 IndexAction,实现了在执行 Action::EVENT_AFTER_PREPARE_DATA_PROVIDER 事件时,即时加载指定的额外资源。
  • SuppressResponseCodeBehavior 需要手动附加到 config 中的 components.response,实现了根据查询参数 $suppressResponseCodeParam,判断是否始终使用 200 作为 HTTP 状态,并将实际的 HTTP 状态码作为内容的一部分包含在响应中。
]]>
0
[extension] devzyj/yii2-attribute-cache-behavior Mon, 05 Nov 2018 05:52:30 +0000 https://www.yiiframework.com/extension/devzyj/yii2-attribute-cache-behavior https://www.yiiframework.com/extension/devzyj/yii2-attribute-cache-behavior devzyj devzyj

ActiveRecord attribute cache behavior

  1. Installation
  2. Usage

提供了一些缓存 ActiveRecord 属性的方法。并且当某些事件发生时,自动使缓存失效。

Installation

The preferred way to install this extension is through composer.

Either run

composer require --prefer-dist "devzyj/yii2-attribute-cache-behavior" "~1.0.0"

or add

"devzyj/yii2-attribute-cache-behavior" : "~1.0.0"

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

Usage

// User.php
class User extends \yii\db\ActiveRecord
{
    use \devzyj\behaviors\ActiveCacheBehaviorTrait;
    
    public function behaviors()
    {
        return [
            [
                'class' => 'devzyj\behaviors\ActiveCacheBehavior',
                //'cache' => 'cache',
                //'defaultDuration' => 604800,
                //'baseModelCacheKey' => ['User', 'PrimaryKey'],
                //'keyAttributes' => static::primaryKey(),
                //'valueAttributes' => $this->attributes(),
            ],
        ];
    }
}


// Using trait methods
// Returns a single active record model instance.
// Sets cache value if there is no cache available for the `$primaryKey`.
$user = User::findOrSetOneByAttribute($primaryKey);

// No changed, cache value exists.
$user->save();

// Changed, cache value not exists.
$user->name = 1;
$user->save();

// Deleted, cache value not exists.
$user->delete();

// Gets cache value for model instance.
$user->getActiveCache();

// Checks cache value exists for model instance.
$user->existsActiveCache();

// Sets cache value for model instance.
$user->setActiveCache();

// Adds cache value for model instance.
$user->addActiveCache();

// Deletes cache value for model instance.
$user->deleteActiveCache();


// Using single key attribute
// ActiveCacheBehavior::$keyAttributes = ['id']
$id = 1;

// get cache
User::instance()->getModelCacheByAttribute($id);
// OR
User::instance()->getModelCache(['id' => $id]);

// exists cache
User::instance()->existsModelCacheByAttribute($id);
// OR
User::instance()->existsModelCache(['id' => $id]);

// set cache
User::instance()->setModelCacheByAttribute($id, $value, $duration, $dependency);
// OR
User::instance()->setModelCache(['id' => $id], $value, $duration, $dependency);

// add cache
User::instance()->addModelCacheByAttribute($id, $value, $duration, $dependency);
// OR
User::instance()->addModelCache(['id' => $id], $value, $duration, $dependency);

// delete cache
User::instance()->deleteModelCacheByAttribute($id);
// OR
User::instance()->deleteModelCache(['id' => $id]);

// get or set cache
User::instance()->getOrSetModelCacheByAttribute($id, function ($behavior) use ($id) {
    $condition = $behavior->ensureActiveKeyAttribute($id);
    $model = User::findOne($condition);
    return $model ? $model->getActiveCacheValue() : false;
}, $duration, $dependency);
// OR
$condition = ['id' => $id];
User::instance()->getOrSetModelCache($condition, function ($behavior) use ($condition) {
    $model = User::findOne($condition);
    return $model ? $model->getActiveCacheValue() : false;
}, $duration, $dependency);

// trait method: find and return ActiveRecord from cache or database
User::findOrSetOneByAttribute($id, $duration, $dependency);


// Using composite key attribute
// ActiveCacheBehavior::$keyAttributes = ['id1', 'id2']
$id1 = 1;
$id2 = 2;
$ids = [$id1, $id2];

// get cache
User::instance()->getModelCacheByAttribute($ids);
// OR
User::instance()->getModelCache(['id1' => $id1, 'id2' => $id2]);

// exists cache
User::instance()->existsModelCacheByAttribute($ids);
// OR
User::instance()->existsModelCache(['id1' => $id1, 'id2' => $id2]);

// set cache
User::instance()->setModelCacheByAttribute($ids, $value, $duration, $dependency);
// OR
User::instance()->setModelCache(['id1' => $id1, 'id2' => $id2], $value, $duration, $dependency);

// add cache
User::instance()->addModelCacheByAttribute($ids, $value, $duration, $dependency);
// OR
User::instance()->addModelCache(['id1' => $id1, 'id2' => $id2], $value, $duration, $dependency);

// delete cache
User::instance()->deleteModelCacheByAttribute($ids);
// OR
User::instance()->deleteModelCache(['id1' => $id1, 'id2' => $id2]);

// get or set cache
User::instance()->getOrSetModelCacheByAttribute($ids, function ($behavior) use ($ids) {
    $condition = $behavior->ensureActiveKeyAttribute($ids);
    $model = User::findOne($condition);
    return $model ? $model->getActiveCacheValue() : false;
}, $duration, $dependency);
// OR
$condition = ['id1' => $id1, 'id2' => $id2];
User::instance()->getOrSetModelCache($condition, function ($behavior) use ($condition) {
    $model = User::findOne($condition);
    return $model ? $model->getActiveCacheValue() : false;
}, $duration, $dependency);

// trait method: find and return ActiveRecord from cache or database
User::findOrSetOneByAttribute($ids, $duration, $dependency);


// Using database transactions, and the `commit()` time is too long
$transaction = $db->beginTransaction();
try {
    // old cache key.
    $oldKey = $model->getActiveCacheKey();
    
    // update
    $model->attributes = $attributes;
    $model->save();
    $transaction->commit();
    
    // delete old cache.
    $model->deleteModelCache($oldKey);
} catch (\Exception $e) {
    $transaction->rollBack();
    throw $e;
}
]]>
0
[wiki] Using multiple models in an identity Wed, 23 Jan 2019 17:41:45 +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 confing/main.php:

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

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

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

        return $this->_user;
    }
}

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

]]>
0
[news] Redis extension 2.0.9 released Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/news/188/redis-extension-2-0-9-released https://www.yiiframework.com/news/188/redis-extension-2-0-9-released samdark samdark

We are very pleased to announce the release of Redis extension version 2.0.9 fixing zrangebyscore and adding >, <, >= and <= support to ActiveQuery.

See the CHANGELOG for details.

]]>
0
[news] Sphinx extension 2.0.11 released Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/news/187/sphinx-extension-2-0-11-released https://www.yiiframework.com/news/187/sphinx-extension-2-0-11-released samdark samdark

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

See the CHANGELOG for details.

]]>
0
[news] Twig extension 2.2.1 released Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/news/186/twig-extension-2-2-1-released https://www.yiiframework.com/news/186/twig-extension-2-2-1-released samdark samdark

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

See the CHANGELOG for details.

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

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

See the CHANGELOG for details.

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

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

See the CHANGELOG for details.

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

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

See the CHANGELOG for details.

]]>
0
[news] Auth Client extension 2.1.7 released Thu, 20 Sep 2018 07:26:26 +0000 https://www.yiiframework.com/news/182/auth-client-extension-2-1-7-released https://www.yiiframework.com/news/182/auth-client-extension-2-1-7-released samdark samdark

We are very pleased to announce the release of Auth Client extension version 2.1.7. It fixes OAuth2 client unsetting scope on defaultReturnUrl. Previously it was causing bad request from recent version of Google provider.

See the CHANGELOG for details.

]]>
0
[wiki] Update and Delete buttons on Breadcrumb Wed, 23 Jan 2019 17:41:45 +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
[news] Auth Client extension 2.1.6 released Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/news/181/auth-client-extension-2-1-6-released https://www.yiiframework.com/news/181/auth-client-extension-2-1-6-released samdark samdark

We are very pleased to announce the release of Auth Client extension version 2.1.6. It upgrades VKontakte API used to version 5.0 and fixes a couple of bugs related to OpenID and canceling login in auth form.

See the CHANGELOG for details.

]]>
0
[news] Replacing the forum software, moving to Discourse Mon, 03 Sep 2018 15:47:12 +0000 https://www.yiiframework.com/news/180/replacing-the-forum-software-moving-to-discourse https://www.yiiframework.com/news/180/replacing-the-forum-software-moving-to-discourse CeBe CeBe

A few month ago we have replaced the old Yii Framework website with a rewritten version in Yii 2. While developing the new site, we also discussed the replacement of the old IPB forum software with a more modern solution, but replacing the forum together with the site would have been too much work to do at once.

From a long discussion, which started already a few years ago, we have now evaluated different forum software and decided to go with Discourse, which is an open source forum software made by the people who created also StackOverflow. We are going to replace the old forum with a Discourse instance starting tomorrow (September 4, 2018).

Here is a list of things that are going to change:

  • User accounts will be managed by the website, there is no duplicate login as we have it now, and all users are signed in to the forum via SSO.
  • Forum categories, topics and posts are migrated from the old forum, so no content will be lost (we might re-arrange the categories though).
  • Links from the old forum should all be redirected to the new location. If you hit broken links, please report those to us!
  • Watched topics and watched forums are not going to be migrated, so if you want to get notified about new posts, make sure to visit the new forum and configure your notification settings as well as update watched topics.
  • User badges on the website do not include the forum posts anymore, instead we are using the Badge system by Discourse, which has a lot more badges than we had before.
  • Discourse allows you to configure it to behave like a mailing list, so if you prefer to take part in Yii discussions from your email client, you can do that now.

In case you have problems logging in to the new forum, please use the Contact form or Chat to get help.

There is a forum topic for discussion on this announcement.

]]>
0
[news] New member joining Yii team as primary Yii 3.0 developer Fri, 31 Aug 2018 22:23:17 +0000 https://www.yiiframework.com/news/179/new-member-joining-yii-team-as-primary-yii-3-0-developer https://www.yiiframework.com/news/179/new-member-joining-yii-team-as-primary-yii-3-0-developer samdark samdark

Andrii Vasyliev, @hiqsol joined Yii team. Andrii uses Yii daily for his team projects and is very interested in framework moving forward.

He's from Kiev, Ukraine and is part of HiQDev team same as another long term Yii team member, Dmytro Naumenko (@SilverFire).

His primary focus will be refreshing Yii architecture splitting it into more packages to achieve more frequent independent releases and making Yii core more robust.

]]>
0
[wiki] When to use Active Record Wed, 23 Jan 2019 17:41:45 +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
[news] Yii 1.1.20 is released Fri, 06 Jul 2018 18:12:52 +0000 https://www.yiiframework.com/news/178/yii-1-1-20-is-released https://www.yiiframework.com/news/178/yii-1-1-20-is-released CeBe CeBe

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

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

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

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

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

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

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

]]>
0
[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
[news] Yii adopts SemVer since version 3.0.0 Wed, 23 Jan 2019 17:41:45 +0000 https://www.yiiframework.com/news/177/yii-adopts-semver-since-version-3-0-0 https://www.yiiframework.com/news/177/yii-adopts-semver-since-version-3-0-0 samdark samdark

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

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

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

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

Yii 2.0.x versioning stays as is.

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

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

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

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

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

Full changelog is available at GitHub.

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

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

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

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

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

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

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

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

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

Plugins

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

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

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

Project Setup

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

    runtime - right click - Mark Directory As - Excluded

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

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

PHPUnit and Codeception

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

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

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

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

You can now run your tests directly from PHPStorm.

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

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

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

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

My config/web.php

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

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

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

Model scholl:


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

Model Teacher:


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

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

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


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

                ],
            ],
        ]
    ];
}

To use login:

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

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

For restrict access in views:

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

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

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

Criticism, suggestions and improvements, use the comments

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

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

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

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

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

    And that's it!

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

]]>
0
[wiki] Yii2 RESTful API with OAuth 2.0 Thu, 08 Nov 2018 00:08:15 +0000 https://www.yiiframework.com/wiki/862/yii2-restful-api-with-oauth-2-0 https://www.yiiframework.com/wiki/862/yii2-restful-api-with-oauth-2-0 sirin_ibin sirin_ibin

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

Overview

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

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

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

Developer Dashboard

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

Why Yii2?

Yii2

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

What is a RESTful API?

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

Something about OAuth 2.0

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

DEMO

http://developers.yii2.nintriva.net/

Login: developer/developer

Source Code

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

Official Documentation

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

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

Installation instructions

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

Similar API Implementation in NodeJs,Laravel &GoLang

Expressjs 4.15/Mysql RESTful API with OAuth2

Expressjs 4.15/MongoDb RESTful API with OAuth2

Laravel 5.5 Lumen 5.5/Mysql RESTful API with OAuth2

GoLang/MongoDb Microservice with OAuth2

Linkedin Post1

Linkedin Post2

Sirin K

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

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

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

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

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

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

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

you will get url like this.

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

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

A Yii2 Gridview designed specifically for reporting

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

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

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

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

Why is this significant

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

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

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

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

or add:

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

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

php composer.phar update

to get the updated package on your application install.

Widget Setup

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

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

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

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

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

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

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

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

Usage

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

Column Configuration

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

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

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

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

Usage

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

for more info see: yii2.percipero.com

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

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

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

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

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

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

My method for handling sub-domains

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

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

common/config/bootstrap.php

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

Create common/components/UrlManager.php

<?php
namespace common\components;

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

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

    protected $_hostInfo;

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

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

        return $domain;
    }

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

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

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

}

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

Add this to your config under the components array:

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

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

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

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

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

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

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

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

or to get the SQL with all parameters included try:

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

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

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

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

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

Imagem da relacao

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

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

Script SQL the ralation has.

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

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

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

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

Model Tests:

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

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

Step 3: Simple Removal Functions in controllers:

public function actionDeletarTest($id)
  {

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

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

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

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

  }

Other Methods

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

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

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

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


public function actionDeleteTheRelation($id)
  {


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

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

  }

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

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

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

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

The code

Here is an implementation for Yii 1 of mentioned solution.

class ImportCommand extends CConsoleCommand
{
    const BORDER_WIDTH = 80;

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

        $this->drawBorder($message);

        $this->readStdin();

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Execution

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

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

yiic import

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

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

]]>
0