Yii2 2.0.14 released; bringing with it some excellent changes.

  • The Yii2 team has release the latest version of the Yii2 framework. With it comes improvements in the following (but not limited to) areas:
  • Scalability and concurrency
  • Validator enhancements
  • Behaviors
  • Databases and ActiveRecord
    • Custom data types and object conditions
    • Query Builder flexibility
    • Upserts
    • Schema builder and migrations
    • New query caching syntax
    • Active Record relations
  • Security
  • Events
  • APIs, serializers and filters

… and much more. Head over to the release notes to read about it all the changes. It is defiantly worth the update.

RE-post: My personal experience migrating a module rom Yii1.x to Yii2.x

(Originally posted on the Sourcetoad Blog circa 20015)

Yii is an amazing framework. As it has been iterated on version 2 is now out and is quickly picking up adoption. With this comes the need to migrate components, modules, and a whole slew of other logic. This blog is a few pointers that we picked up along the way while doing a forum migration. This was the first feature migration we did in house, it was an interesting experience.

RTFM, this may seem a no brainer but read the manual, specifically about the Yii1->2 changes. http://www.yiiframework.com/doc-2.0/guide-intro-upgrade-from-v1.html
Use a source control system. GiT, SVN, Mercurial, etc.
Run the tests, make change, run tests, refactor, run tests, commit, run tests
Pick a specific part of logic / cord to replace. GridViews, DetailList, etc. Do one chunk at a time.
Give back to the community, no one like that guy that takes and takes and never gives back.

One of the most obvious changes has been the inclusion of autoloading classes. Good bye require_once(‘composer/autoloader.php’), hello namespacing. With this change the class names have become much more sane. No more ‘CBaseModel’, now \BaseModel.

The model level logic has seen a substantial change as well. “…In 1.1, query building was scattered among several classes, including CDbCommand, CDbCriteria, and CDbCommandBuilder. Yii 2.0 represents a DB query in terms of a Query object that can be turned into a SQL statement with the help of QueryBuilder behind the scene…” (Yii2 documentation). Now queries are similar this example:

$modelData = \packageName\common\models\ModelName::find()->andWhere([‘id’ => $userId])->one();

Idealy this would return the user’s data from the specified model.

Moving on the view level widgets have had a measurable change as well:
Old:

$this->widget('yii.widgets.grid.CGridView', array(
    'dataProvider'->$dataProvider,
    'columns'=> array(
        'title',         // display the 'title' attribute
        'category.name', // display the 'name' attribute of the 'category' relation
        'content:html',  // display the 'content' attribute as purified HTML
        array(           // display 'create_time' using an expression
            'name'=>'create_time',
            'value'=>'date("M j, Y", $data->create_time)',
        ),
        array(// display 'author.username' using an expression
            'name'=>'authorName',
            'value'=>'$data->author->username',
        ),
        array(// display a column with "view", "update" and "delete" buttons
            'class'=>'CButtonColumn',
        ),
    ),
));

New:

GridView::widget([
    'dataProvider' => $dataProvider,
    'columns'       => [
        [
            'class' => 'yii\grid\SerialColumn'
        ],
        'title',        // display the 'title' attribute
        'category.name',// display the 'name' attribute of the 'category' relation
        'content:raw',  // display the 'content' attribute as purified HTML
        [               // display 'create_time' using an expression
            'name' => 'create_time',
            'value' => 'date("M j, Y", $data->create_time)',
        ],
    ],
    [// display 'author.username' using an expression
        'name' => 'authorName',
        'value' => '$data->author->username',
    ],
    [
        'class' => 'yii\grid\ActionColumn'], //CRUD UI elements
    ]
]);

The astute eye will notice that the base code has simply been updated to the current recommendations. the main change being how the widget is instantiated. The astute will also notice the new column’s `SerialColumn` and `ActionColumn`. These two handy classes provide serialized numbering and CRUD UI elements for the column data. DetailView, ItemView, etc have all been iterated on in this way.

That is all the time we have for today but we hope this has provided insightful. It is highly recommended you take a look at the documentation provided by the Yii team for even more details. http://www.yiiframework.com/doc-2.0/guide-intro-upgrade-from-v1.html

Yii2-starter-kit update…and shameless plug.

 

A project I heavily rely on these days recently got some updates. Shameless plug: I was kinda  a part of a bunch of them. utf8-mb4 update for MySQL data sources, RBAC CRUD UI module, and a queue module will be merged in soon. Days like this make it fun to be a software person. 😀

Checkout the starter kit here: Yii2 Starter Kit

PSA: Do not use Codeception DB and Yii2 modules together…

…specifically the Yii2: ORM and DB module and transactions. The Yii2 $I->seeRecord() & related methods do NOT use the same connection ID as the DB module. So doing actions such as importing fixtures and executing actions via the ActiveRecord abstraction happen on the frameworks connection.

Trying, then, to do actions like $I->seeInDatabase() and related DB modules actions will fail, almost always. Why? The Db module uses a separate connection, as defined in the suite.yml (acceptance/functional/unit) files.

So, from here out I will not be using the two modules together. Either use Yii2+Fixtures or use the DB+dump.sql. Both, together, is problematic at best.

Did a thing today, ‘nother new package.

New Package: Stripe + CommandBus + Yii2

I got tired of writing out the entire Stripe class requirements coupled with the need to trigger stripe events from different areas of the application  motivated me to create this package. It is by far NOT production ready but lays the ground work and ideas for the package. Take a look, leave a comment, contribute.

Also have another one in the works that combines Google Chrome, Codeception, headless browser testing, and replacing PhantomJs (since the maintainers are deprecating the project).

Yii2 hasOne vs hasMany param order

hasOne()

* 
* public function getCountry()
* {
*     return $this->hasOne(Country::className(), ['id' => 'country_id']);
* }
*

hasMany()

*
* public function getOrders()
* {
* return $this->hasMany(Order::className(), ['customer_id' => 'id']);
* }
*

Notice the opposite order? The docs explain why but it’s still confusing.

Ticket submitted.

Yii2 AR SQL Verbs; Y-U-SO-WEIRD?

Yii2 being an active record style DB abstraction AND needing to support a wide range of database technologies facilitated creating the standard insert / select / update / delete functionality inside the Active Record model layer. While most of implementation makes sense some of it is not intuitive. Herein is a TL;DR of the 4 major commands and the *All() version if applicable.

 

select / selectAll (in Yii2 this is termed ‘find’)

\Class::find([{array of criteria}])->one(); OR \Class::findOne([{array of criteria}]);

\Class::find([{array of criteria}])->all(); OR \Class::findAll([{array of criteria}]);

 

insert / insertAll (termed ‘save’)

$model = new \Class({column values as array});

$model->save();

No saveAll() implementation by default

 

update / updateAll

$model = \Class::find({column values as array});

$model->setAttribute(s)({string or array of SQL SET keyed values})

$model->save();

 

Class::updateAll([{array of criteria}], {string to Key = Value pairs for SQL SET})

 

delete / deleteAll

\Class::delete({string of criteria})

\Class::deleteAll({string of criteria})

 

Bonus: Yii2 also has the ability to create database commands and bypass the Active Record abstraction altogether: Yii::app()->db->createCommand({string  of SQL command}).

 

Now, lets look at MySQL / Maria / MsSQL / Postgra default immplimentation of the same actions:

select/all

Select {string of keyed values} FROM {string of source} WHERE {string of keyed values}

 

insert/All

Insert Into {string of source} VALUES {string of keyed values}

 

update/All

Update {string of source} Set {string of keyed values}

 

delete/All

Delete From {string of source} Where  {string of keyed values}

 

See a pattern there? string source, key/value data sets. And minus Select all start with the data source followed by the command, the the key/value criteria.  And even select makes sense when you treat the field names as a string substitution for `select {needle(s)} from {source|`.

 

It is not that AR is bad, nor that Yii2 had a lack of effort. Trying to support the feature set of multiple database technologies, active record, createQuery, best practices, security, and community requests is daunting, hands down. Maybe I’ll write a package to normalize the base 4 verbs for MySQl/MariaDB…

 

 

Quick little thing.

Was sad to see Yii2’s getOldAttributes() did not have to ability to limit based on a provided array; whereas getAttributes() does take an array to limit the returned attributes. So I whipped this up right quick:

/**
 * @param array $array
 *
 * @return array
 */
public function getOldAttributes($array = [])
{
    $returnData = parent::getOldAttributes();

    if (!empty($array)) {
        $returnData = array_intersect($array, $returnData);
    }

    return $returnData;
}

Simple little thing but super handy.