Tuesday, March 30, 2021

Converting an Application From Yii2 to Yii3

Converting Yii2 to Yii3

A Minimalist Conversion Example

I’ll admit, I put off playing with Yii 3 for quite a while because I was daunted by the quick peeks into the code base and sample applications. The differences between configuring and bootstrapping a Yii 2 application vs a Yii 3 application are significant. At first glance, the two versions of a base application are completely different. But, once you start digging in, the similarities become apparent and you can start to draw the connections between the Yii 2 methodologies and the Yii 3 counterparts. These are my first impressions and the results of my own investigations thus far. I expect things to continue to evolve as the Yii 3 project advances.

PLEASE NOTE: Yii 3 is *not* yet ready for production release. This blog is an attempt to get more people playing with it and correspondingly, more people involved with providing feedback and assistance in developing and supporting the project. If you are not feeling adventurous, table this project for when there is a stable release and official documentation. Check the Release Cycle for production timelines and updates.

Sunday, February 9, 2020

Takeaways from SunshinePHP 2020


It's been a bit of a whirlwind year so far and it's only February!! I feel like just yesterday I was in Belgium for PHPBenelux (oh wait, it pretty much was ... will have to post on that later).

If you are here because you're looking for the slides from either the tutorial session or the general session from SunshinePHP, you can find them here:


Thursday, October 31, 2019

Setting up Docker Desktop on Windows 10

I was speaking with someone this morning that was attempting to get their stack running on Windows, but running into issues with volume paths. It emphasized for me that it's been a while since I attempted to work with Docker on Windows and I should probably refresh that, so I did!

This is a quick walk through of how to set up Docker Desktop on Windows 10 Pro, with some of the common pitfalls, and a demo stack you can use to verify that your Docker installation can properly access the volumes created on Windows drives.


Wednesday, September 25, 2019

Quick Thoughts from Cascadia PHP

Having just recently returned from Cascadia PHP, where I had the pleasure to be presenting on Docker and how to containerize your development environment, I wanted to take a moment and jot down some thoughts about the nature of the PHP Community and supporting your local conferences.

This was a smaller conference than I'd been to so far, but with that decreased size came an increased level of connectedness between all of the attendees, which really enhanced the sense of community. I had the pleasure of meeting many people from the local area and learning their stories, as well as many folks who flew in from around the country.  I was strongly reminded of what it was like to be just embarking on your development career - it's been a long time since I've worn those shoes - stick with it and keep pushing yourself. =)

As with every conference that I attend, I walked away with a list of "research homework" to do, which is wonderful - if we're not learning, we're not growing.

A couple of those homework/research points:
  • Using middleware when converting legacy applications
  • The PHP-FIG group - getting involved
For anyone curious, the slides to my presentation can be found on SlideShare.

If you happened to be at the conference, please send in your feedback via Joind.in - your constructive feedback is always valuable and appreciated!

If you haven't been to a conference (or just haven't been to one in a while), you really are missing out on a wonderful and supportive community of people. Everyone has something to teach someone else and something they can learn from someone else.  (This is a reminder to myself for when I get so bogged down with work that I wonder if I really have time to go to this event or write that blog ... yes -- make the time.)

Thursday, May 30, 2019

Yii2 Queue with Redis on Docker Swarm is a game changer

I don't know why I haven't utilized this before, but the yiisoft/yii2-queue is a fantastic way to quickly and easily split some of your application processing out to asynchronous workers.

Getting it set up with a redis storage engine on a docker stack is super simple -- we just add a persistent redis service to the docker stack, configure the application to include the queue component, and move our slow process(es) into a queue job.

Since we're using a Docker Swarm stack we don't need to worry about setting up a cron or systemd service, we set up the queue listener as it's own service in the stack, which also gives us the ability to scale the queue workers dynamically as the need arises.

Tuesday, May 7, 2019

DockerCon Hallway Track - Logging to a NFS mounted Docker Volume

Recently at DockerCon I decided to check out the whole 'Hallway Track' concept and share a sticky situation we ran into at work. If you've never been, the Hallway Track is a coordinated effort to get conference attendees talking to one another and sharing knowledge. You post your topic or peruse the posted topics and they facilitate connecting people together to discuss face to face. I was amazed at the number of people who requested to talk to me about our experiences with the complications of writing application logs to a NFS mounted docker volume. The official title was "Lessons learned: Why writing to flat file logs in an NFS mounted docker volume is unwise".

Wednesday, February 13, 2019

Code Analysis with Exakat on Docker

One of the neatest things I learned about last week at SunshinePHP, was how Exakat can be used to perform static analysis of a codebase to help formalize your code review processes.  It's a great tool for determining how consistent you and your team are being with your code, and has indicators to show you how closely your code base aligns to each of the major PHP versions -- an excellent way to check backward compatibility and/or whether you're ready for a PHP upgrade or not. 

With Docker, it's extremely easy to get things running!

Monday, February 11, 2019

Notes from SunshinePHP 2019

This conference blows me away every year! There is always so much to learn and to share.  This year every attendee was able to receive their very own ElePHPant - so my herd continues to grow (ok, so I actually have a menagerie, since it includes a few Docker whales as well!)

Some of my biggest take aways from this year's conference:

  • MySQL 8 and x shell via docker
  • Security testing technique
  • Swoole! (Async. PHP!!!)

Once again, I'm renewing my determination to pick the blogging back up - it may not have as many Yii specific examples, since I tend not to run into quite as many road blocks there as I used to (9 years with a framework will do that) but I'm constantly running into IaaS challenges that others may value insight into.  If only there were more hours in a day ...

Friday, October 19, 2018

ZendCon & Open Enterprise 2018

Wow, can't believe how long it's been since I've taken the time to sit down and post on this blog! Just goes to show how crazy and busy life can get. I just got back from ZCOE 2018 - ZendCon & Open Enterprise, where I had the pleasure to present a variety of information about how to incorporate Docker into your daily workflow and use it effectively.  It was my first time at ZendCon, and I was very impressed with the conference! There was a lot of great information presented in the general sessions and all of the keynotes were full of both historical information about some of the key tools and aspects of the open source community and information about where those tools are heading in the future. I was particularly intrigued by the information about asynchronous PHP and Swoole. I am way too old school to be excited about anything that screams of going backward (which is where my my mind jumps whenever anyone starts talking about how awesome functional programming is - or serverless, which is just functional programming on demand - I jump back to the pre-OOP days of functional chaos in my head), but async. is something that I can see myself getting behind. Super excited to look into it further, in addition to all the other tips and tidbits I picked up at the conference.

For anyone curious, the slides to my presentations can be found on SlideShare

If you happened to be at the conference, please send in your feedback via Joind.in - your constructive feedback is always valuable and appreciated!

Thursday, September 28, 2017

HacktoberFest

Despite the crazy busy schedule (I miss my time to sit and write these blogs) and the inability to figure out how to squeeze 10 more hours into any given day, the team at work has decided to participate in HacktoberFest - just too cool to pass up! If you're not familiar with it yet, check it out and find a little time to give back to the open source community in a fun way.

https://hacktoberfest.digitalocean.com/

I'll probably be focusing my efforts on the Yii front there, since it's a project that I use daily and am not sure how I lived without it before ... What are you passionate about and willing to sacrifice a little personal time to see thrive?

Saturday, March 19, 2016

Swivel Extension for Yii

In my last post, I mentioned that I was looking forward to making a Swivel extension for Yii. I'm excited to share that I've FINALLY found the time to do so.

It's a fairly straight forward extension, simply providing access from the application to a Swivel component which interacts with the core Swivel library, and which handles the general bucket assignment for users as swivel is accessed. I've also provided a class for integrating the existing Swivel logger over to the primary Yii Logger, and provided a data structure and model for storing the list of features for the application.

The extension is available on the Yii Framework Extensions list, from the GitHub repository or as a composer package.

It's really designed to be installed via composer:
composer require "dhluther/yii-swivel":"~1"

I've tried to keep it lean, but provide a good bit of information about how to implement it and how the Swivel features work on the Yii-Swivel Wiki on GitHub.

I will be creating a 2.0 version shortly as well.

Enjoy! I hope others find it as useful as I think I am going to, and huge props to the Zumba team that developed it and to Stephen Young and his presentation at SunshinePHP 2016!

Sunday, February 7, 2016

SunshinePHP 2016 Conference

I had the opportunity this weekend to attend the SunshinePHP conference in Miami. What an amazing group of people who are passionate about what they do. The theme for the weekend centered on collaboration and supporting the open source community, something that is near and dear to the heart of many Yii developers. It was a wonderful thing to meet so many people from around the world who believe in supporting community. A special shout out to Josh Holmes and Michelangelo van Dam who were extremely outgoing, encouraging, and full of tidbits of wisdom which they were willing to share.

I wanted to take a few minutes and share some of my hot takeaways from the weekend.

  • Docker - If you don’t know what it is yet, you need to go check it out. Docker is "an open platform for distributed applications for developers and sysadmins." Docker enables you to quickly compartmentalize processes on your server, while leaving them with access to the same base OS. Through port forwarding, shared folders and other means (built in and easily configurable), you can enable those processes to communicate. This is useful when you want to test a single application installation against multiple versions of PHP or multiple versions of MySQL. It’s also useful when you are trying to standardize a development platform or delivery system. In fact, there are so many potential uses for this technology in streamlining and standardization that I can’t even begin to recount them all. Long story short - if you haven’t looked at it yet, do so. If it still doesn’t make sense after reading about it, ask ;)
  • Swivel - Ok, this is pretty cool - the guys over at Zumba fitness have come up with a slick library for strategy driven, segmented feature toggles. These allow you to release new features in Canary Releases, perform A/B testing, and implement the features in a way that keeps the traditional feature flag system’s potential complexity from overloading your codebase and leading to a lot of technical debt. Swivel is currently limited to a 10 cohort (or buckets as they call it) system, which you evenly split your users into, giving you 10% user base segments for whatever feature you’re going to test or release. They currently have a CakePHP plugin for it, and I’m looking forward to working on a Yii extension for it.
  • Team City - Who knew?? JetBrains has a CI product. I guess I’ve kept the blinders on PHPStorm for so long (which I love and don’t know how I lived without), that I missed the news on this one. I haven’t looked into the details yet, but the PHPStorm developers that were at the conference said they couldn’t make PHPStorm without it, and that’s enough of a recommendation for me!
There’s so much more, I could go on for hours about Graph Databases and RUM, Performance Monitoring and PHP Pipelines, just to name a few. If it’s been awhile since you’ve been to a conference, I highly recommend that you go. Find a conference or a user group nearby, or take a leap of faith and visit one that changes not just your routine, but your whole perspective ;)

Thursday, December 10, 2015

Testing in Yii 2.0 with Codeception - Fixture Data

I'll admit it -- I'm a phpunit addict. Switching to codeception has been a bit of a struggle for me, just because it feels like it should be intuitive, but it's different enough from what I'm used to that it's taken me a few days to really wrap my head around it. My biggest struggle? Trying to get fixture data to automatically load and unload when functional and acceptance tests are run. I finally dug through the yii2-app-advanced code and discovered the FixtureHelper!! The FixtureHelper is the missing link in getting your fixture data to automagically load and unload when the functional and acceptance tests are run.

Friday, December 4, 2015

Flash Messages and Redirects in Yii2

Using Flash messages in Yii 1.1.* is something that I have done for so long, and so commonly, that I take it completely for granted. Whenever a user performs some action and the processing generates some information I want to convey back, I plug that information into a success, warning, info or error flash message, pop in a redirect for that situation and VOILA! After my processes are finished, the flash message is displayed to the user.

For example, in Yii 1.1.*, I have a handy action that is called if a user needs to retrieve their password from the database. It was written well back, around 1.0.6-ish, but still gets the job done nicely. Look up the user by the posted email, if the user is found, send the user an email and set a success message, otherwise, set an error message. Once that's done, redirect the user to the previous page. Otherwise, notify them that there was an error and keep going on.

When I converted this particular action to Yii2 it kept losing my flash messages. If I took out the redirect after successfully processing and sending the email, it was fine -- but I need the redirect to prevent inadvertent multiple form submissions etc. What to do?!? After scouring the internet and Yii forums, and finding multiple instances of people complaining about it not working but no good solutions or notes other than 'working as intended', I finally - FINALLY - realized that it is the redirect method itself that is, while stopping any output to the screen, not actually stopping the currently processed action. If I was more observant, I would have noticed it in the example of a controller redirect here: http://www.yiiframework.com/doc-2.0/guide-structure-controllers.html

Tuesday, November 11, 2014

Active Relations from Yii 1.1 to Yii 2.0

In Yii 1.1.x relations were defined by an array within the model class. In Yii 2.0 that is no longer the case. Relations are now defined by getter methods within the model. For the complete specification see Working with Relational Data in the Yii 2.0 Guide.

Saturday, April 19, 2014

Making the switch from Yii 1.1 to Yii 2.0 - Part 2: Getting Started

Probably my biggest hurdle in getting started with Yii 2.0 (aside from getting my hosting company to upgrade my server from PHP5.2 to 5.4) has been understanding the changes to the application structure and the vast difference between the basic application and the advanced application. Since my personal site runs on a subdomain, this greatly complicated the issue for me. I needed something more than the basic application, but the advanced application was way too much overkill. I finally went with the advanced application, but now that I understand how the composer works to distribute the skeleton files, I'm looking forward to creating something that's between the two.

There is way too much to cover in a single blog, so this is just a look at the basic structure and front end changes that you need to know to get up and running in 2.0.

If you're past all of this and looking to dive into the nitty-gritty detail changes, I suggest you read the official documentation on upgrading.

Tuesday, March 11, 2014

Setting the CDbConnection for Active Records within a Yii Migration

I use migrations whenever possible within Yii applications to help ensure consistency between implementation. I have multiple development environments, a staging environment and a production environment. I really don't want to have to manually issue a lot of sql queries or yii commands if I don't have to. Migrations make that possible and can be integrated automatically in the build process for deployment.

Occasionally, I need to convert some old data into a new structure, and I can do this via the migrations as well!

Create a basic migration to translate data:

For example, to query a set of data from an old table, and create a new set of records from it (that may have additional logical processes added beforeSave etc.) I could start off by doing the following in my migration:

public function up()
{
  // Query for the existing record data
  $results = Yii::app()->db->createCommand()
    ->select('*')
    ->from('tbl_old')
    ->queryAll();

  // Ensure that if we fail, we start with a fresh slate
  try {
    foreach( $results as $row )
    { 
       $m = new NewModel();
       // assign attributes from $row[] that should be
       // mapped to the new model applying any new
       // logical manipulations required
       if (!$m->save())
       {
         throw new Exception(
            CVarDumper::dumpAsString( $m->errors )
         );
       }
    }
  } catch ( Exception $e )
  {
     echo $e->getMessage(), PHP_EOL;
     $this->truncate('tbl_new');
     // indicate migration failure
     return false;
  }

  // acknowledge success
  return true;
}


If you only have one db connection in your application, this will work fine. But, if you also have a test database that you need to migrate, it will quickly fail due to duplicate primary keys, or write double the data in your primary database, rather than your test database.

Update the migration to handle alternate connection components:

To update the migration to work with a different connection, we simply need to add a few lines that specify which connection to use, as follows:

public function up()
{
  // Query for the existing record data 
  // Use migration's db connection rather than Yii::app()->db
  $results = $this->getDbConnection()->createCommand()
    ->select('*')
    ->from('tbl_old')
    ->queryAll();

  // Set the static connection property for active records to the migration's 
  // connnection
  CActiveRecord::$db = $this->getDbConnection();
 
  try {
  //  ... the rest remains the same
  }
}


Now, I can run my migration on the alternate connection with no problems, and no pulling of hair!

./yiic migrate --connectionID=db_test


On the Yii2 front, I was side tracked by the fact that I can't find an equivalent to the CViewAction (which I use extensively), and so much of the main layout involves new widgets in static method form, but I will get back to it soon!

Tuesday, February 4, 2014

Making the switch from Yii 1.1 to Yii 2.0 - Part 1: Before You Begin

So, over the weekend I decided that it was time to dive into Yii2 and start getting familiar with it and be prepared for the official beta release coming up. I've been reading the forums about it since the 2.0 board was first opened, and I thought I was in a pretty good place to start from. The first thing I learned, was that I have a lot to learn before actually starting to convert any of my applications into Yii2.

What You Need to Know Before You Start!


Yii2 takes "full advantage" of some of the "newer" (I know it's been out a long time, but some of us haven't had the liberty to use it) capabilities of PHP - namely (pun intended) requiring PHP5.4 as a minimum, and using Composer to create new Yii applications. They've also switched out the standard PHPUnit tests in the application for Codeception.

If you're at all like me and have been nose to the grindstone on servers locked into PHP in the 5.3 (or lower) family, this will come as quite a system shock, even when you know it's coming ... I'm ashamed to admit that I looked at an array in 5.4 syntax and tried to figure out why there was JSON code in my PHP file.

So, forget all the implementation differences between Yii 1.1 and Yii 2.0 for now -- If you're not already fluent with PHP 5.4, Composer and Codeception, spend a week getting there.

Composer - PHP Package Manager

The documentation for installing Composer is very straightforward and can be found at http://getcomposer.org

Getting it running on my Ubuntu VM was very straight forward, but on my Macbook I had to go through quite a bit of shenanigans to get XCode updated (required by Composer). I ended up having to uninstall and reinstall XCode before Composer would work properly there. Though the PHP upgrade on the Macbook trumped the PHP upgrade on the Ubuntu machine. So scratch off an evening just getting Composer running smoothly across the board. I believe this will be the preferred method of releasing extensions, etc. so if you're planning to move in that arena and aren't already familiar with this, time to read up.

I'm still figuring out all the basics for it, but it seems like a very handy way to keep packages maintained, and I'm looking forward to really becoming familiar with it.

PHP 5.4: Namespaces and Arrays

Oh my. So, the namespaces take a lot of getting used to, seeing all the /path/to/myClass::$variable and it seems like it takes up a lot more characters to do something very simple. Lots of power there though, and once you get used to reading it and writing it that way, it will become second nature. For the full list of what's dramatically different, check out the PHP 5.4 migration guide.

Arrays can now be generated with short array tags, and you'll find this extensively in the Yii2 code.
$config = array('something'=>'else','sub'=>array('marine'=>'sandwich'));
becomes
$config = ['something'=>'else','sub'=>['marine'=>'sandwich']];
Much more concise, but will definitely throw you for a loop the first time you see it. It's going to be a while before I can read that as quickly as I can the old style.

CAUTION: Once you start looking ahead, it'll be hard to go back to the old 5.3 ways -- so be sure you're ready!

Codeception Testing Framework

I haven't looked into Codeception very far yet, but it essentially runs all the tests from a 'story' point of view. This is my personal homework for the next few days. If you're as dependent on TDD as you should be, you will want to brush up on this before diving in.

Finally, my favorite ...

Bootstrap 3.1.0

The new sample applications implement Bootstrap 3.1.0 which has been changed significantly from the Bootstrap v2. Bootstrap 3 is designed not just to be mobile responsive, but mobile first. If you're used to using any of the other CSS libraries or the v2 flavors of Bootstrap, spend a little time getting familiar with the changes that have been implemented in the v3 line. It's well worth it.

Once you're FULLY familiar with the syntax changes for 5.4 / 5.5 (whatever your flavor), and Namespaces no longer throw you for a loop, and Composer is installed and functional, it's finally time to start reading
Upgrade from v1 on the Yii2 docs.

I should also mention, my beloved "yiic" command is no more -- it's now "yii"! So if you get ambitious and download the sample applications, don't go searching for yiic, because you won't find it. ;) I'm excited about the advanced application and the init scripts to toggle configurations, but I'm getting ahead of myself here ...

Part 2 should make its appearance this weekend as I will dive into transitioning an old Yii 1.1 application into Yii 2.0

Thursday, January 30, 2014

Saving and Retrieving Encrypted Data in Yii

A few people have commented about using md5 or the PASSWORD() capabilities and how to retrieve their data from their MySQL database when updating user passwords and other encrypted data, so I thought it would be a good idea to spend a little time talking about how you can use the CSecurityManager to handle your encrypted data in a way that keeps it completely secure, but allows you to retrieve the original data.

This is not a new feature, it has been around since Yii 1.0, but it's easy to overlook it you don't handle a lot of encryption or need to worry about much other than the occasional casual user field.

The CSecurityManager works as an application component, so to access it you simply call
// $key is optional, it will default to NULL if you don't pass one
Yii::app()->securityManager->encrypt( $string, $key );

and

Yii::app()->securityManager->decrypt( $string, $key );

The most important thing to remember is that your key has to be the same when encrypting and decrypting! This may seem like a no-brainer, but if you're using different keys for various applications, components, or modules, you can quickly run into complications. I like to store the key as a constant that I can access with the model, so that the model can then intelligently report the data if needed. Of course, you need to consider the security of your models before implementing anything that will allow decrypted access.

Back in this old post about saving encrypted passwords I demonstrated the more traditional MySQL PASSWORD() approach. Using the CSecurityManager to handle your encryption will use essentially the same approach, only you'll update the encryptPassword function as follows:

const KEY_VALUE = 'someRandom123'; // <-- make this good

public function encryptPassword()
{
  // Nothing to encrypt
  if ( $this->userpass == '' )
    return;

  $this->userpass = Yii::app()->securityManager->encrypt( 
    $this->userpass, 
    self::KEY_VALUE 
  );
}

Note: I'm using the password field here since it's the previous example and the one thing most people actually make an effort to encrypt. You can encrypt any data that you save, so please don't feel that this example applies only to password data.

Now, if your administrators need to be able to access the encrypted data so that they can answer questions for people, you need a way for the model to see that data cleanly - hello decrypt! You should be VERY cautious about using this. If you handle the decrypted data lightly you're losing the point of encrypting it in the first place.

/**
 * Return the decrypted value of the field (does NOT assign
 * the decrypted value back to the attribute)
 * @return string
 */
public function decryptPassword()
{
  // Nothing to decrypt
  if ( $this->userpass == '' )
    return '';

  return Yii::app()->securityManager->decrypt( 
     $this->userpass, 
     self::KEY_VALUE
  );
    
}

Remember, as in the original example, you're not going to re-encrypt it before every save, only when the data has been updated or the record is new, unless you're decrypting it by default afterFind, which I do not recommend (see above note about the wisdom of handling decrypted secure data).

If you really want to get fancy with your data storage, you could run an encryption filter on all the attributes before saving, and then decrypt them afterFind so that it's impossible to read anything in the database directly. There may be some merit to that idea if you're on a shared database server, but if you trust your database security then that's probably a lot more complicated than you need to make your data storage for any data that isn't truly sensitive.


So, now looking back to the original post about authentication via database, we should update our authentication a bit:

public function authenticate()
{
  $record=User::model()->findByAttributes( array('username'=>$this->username) );
  if($record===null)
    $this->errorCode=self::ERROR_USERNAME_INVALID;
  else if( $this->password != $record->decryptPassword())  // <-- Note the change
    $this->errorCode=self::ERROR_PASSWORD_INVALID;
  else {
    $this->_id=$record->id;
    $this->setState('title', $record->title);
    $this->errorCode=self::ERROR_NONE;
  }
  return !$this->errorCode;
}

Wednesday, December 11, 2013

Adding Authorship and Publisher data to your site with Yii

Adding the appropriate metadata is actually quite straight forward. If you're not sure what information I'm talking about, please check out my recent blog post on Authorship and when to use it.

Adding the publisher information is the easiest to tackle, as your entire site should be tagged as one publisher, so you can add it to the main layout simply by using the client script manager. The hardest part is making sure you have a brand Google+ page set up and getting the proper ID number.

In your main layout, or wherever you feel it is most appropriate for your situation, simply add:
Yii::app()->clientScript->registerLinkTag( 'publisher', null,
    "https://plus.google.com/{$profileId}"
); 

If you are the only author on the site, you can add your authorship information at the same time. Otherwise, you should add the author metadata only on the pages where it is most appropriate and using the Google+ profile page for the relevant author. You can do this from the Controller action, the view file or in a beforeAction method or a filter of the Controller if you have one author for a whole section of CViewAction pages, etc.
Yii::app()->clientScript->registerLinkTag( 'author', null,  
    'https://plus.google.com/u/0/'.$gPlus.'/'
);


That's really all there is to it!!