Documenting Documentation

I recently waded back into simple web application development (more on how that feels later), and one of the many aspects of coding that I’ve been refreshing myself on is how to best document what I’ve written so my future self doesn’t get too confused over what I implemented or why I implemented it in the way I did. The application is deadly simple, so simple that I hesitate to call it an application. The web page contacts a PHP script via an Ajax call, and the PHP script does its thing, sending back a JSON-encoded object. The client subsequently uses the object to display a message of success or failure.

As I said, deadly simple.

Nevertheless, as simple as the application is, I’ve been researching how best to document PHP and JavaScript. For PHP, the definitive answer appears to be phpDocumentor 2. For JavaScript, there is JSDoc. Here are some additional links that I found useful:

phpDocumentor

JSDOC

Note that I haven’t actually tried generating documentation with either toolset; that’s a completely different challenge. I’ve mostly been following the format so that my documentation can be printed/generated if somebody (aka me!) wishes. And what I’ve come to understand is that learning how to document a language feels almost as complicated as learning the language itself.

 

Getting Travis-CI to work with a PHP Project

First off, Travis CI is only usable through github. It’s a great service that allows tests to be run before pull requests are merged, helping to ensure code stability. It’s a very new service, and PHP support is in flux. Almost daily information changes. So I fear this will be outdated tomorrow. Regardless, I wanted to get this written down.

The magic all happens in the .travis.yml file. It’s a config file that tells travis what to run. It only has a few sections, but they can be tricky. Here is the example .travis.yml for PHP:

language: php

# list any PHP version you want to test against
php:
  # using major version aliases

  # aliased to 5.2.17
  - 5.2
  # aliased to a recent 5.3.x version
  - 5.3
  # aliased to a recent 5.4.x version
  - 5.4

# optionally specify a list of environments, for example to test different RDBMS
env:
  - DB=mysql
  - DB=pgsql

# execute any number of scripts before the test run, custom env's are available as variables
before_script:
  - if [[ "$DB" == "pgsql" ]]; then psql -c "DROP DATABASE IF EXISTS hello_world_test;" -U postgres; fi
  - if [[ "$DB" == "pgsql" ]]; then psql -c "create database hello_world_test;" -U postgres; fi
  - if [[ "$DB" == "mysql" ]]; then mysql -e "create database IF NOT EXISTS hello_world_test;" -uroot; fi

# omitting "script:" will default to phpunit
# use the $DB env variable to determine the phpunit.xml to use
script: phpunit --configuration phpunit_$DB.xml --coverage-text

# configure notifications (email, IRC, campfire etc)
notifications:
  irc: "irc.freenode.org#travis"

Not included libs

Currently this will not work. Their phpunit is requiring libraries that aren’t included in the vm that’s created. Regardless of if your project is using these libraries:

before_script:
  # everything after this point is needed to just use phpunit
  - pear channel-discover pear.phpunit.de
  - pear install phpunit/PHP_Invoker
  - pear install phpunit/DbUnit
  - pear install phpunit/PHPUnit_Selenium
  - pear install phpunit/PHPUnit_Story

Database usage

I use mysql currently. The problem I hit was you can create users, but you can’t grant them privilages. So you HAVE to use the default root user with no password.

env:
  - DB=mysql

# execute any number of scripts before the test run, custom env's are available as variables
before_script:
  - mysql -e 'CREATE DATABASE `quizmo_dev`;'
  # The following is fine, but travis won't allow granting privilages
  # - mysql -e "CREATE USER 'quizmo_dev'@'localhost' IDENTIFIED BY 'quizmo_dev';"
  # - mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'quizmo_dev'@'localhost' WITH GRANT OPTION;"
  # migrating adds all tables
  - quizmo/protected/yiic migrate --interactive=0

Notifications don’t work

I’m assuming this is something they’ll fix soon. I’m just trying to use email notifications — but it never sends an email.

Continuous Integration with PHP on Travis CI and Github

People on high have been preaching the wonder of continuous integration for a while now. It’s been all about Jenkins forever. Jenkins is still the #1 choice for most people, but I recently ran into Travis CI and at least short term, this is going to be the solution for our shop.

What is Continuous Integration for PHP?

CI to most people involves building and running integration tests. PHP clearly doesn’t build, but good PHP still has unit tests / integration tests / functional tests — so CI for PHP is running those tests before code merges.

What makes Travis CI good?

Probably ease of use. There is no setup of a “travis server”. It’s a service that they run. You hook it to a repo you have access to and set up a config file and it’s good to go.

But this only works with github?

That’s probably the biggest detractor. It’s currently built exclusively for use with github. Which is awesome for github projects, but not every project can be on github. We don’t always have control over where our repos are — and not everyone is an open source person.

Posted in Development, Open Source, PHP. Tags: , , , , , . Comments Off on Continuous Integration with PHP on Travis CI and Github »

Back in Time with PHP

I recently had the opportunity to work on a PHP application that was written by a student in 2004. Before the time of PHP frameworks and separation of MVC, when applications had SQL and HTML in the same files. Each page was a form that submitted to itself. Everything contained in one file per page. Pretty crazy, right?

Crazy like awesome. I had so much fun working on features for this old application. It wasn’t just nostalgic, it was like comfort food. Easy and delicious. I’m not really sure how comfort food is “easy”, but just go with it. I was practically begging to do more work on it.

I can’t imagine myself creating a new application like this from scratch, but I’ve been thinking about the benefits. Anyone with just a tiny bit of PHP experience could pick it up and maintain it, there’s no technology ramp-up time. A project like this could be orphaned and passed around between anyone. It could be used to teach people basic PHP within the organization. Say, people who are so Java-centric they refuse to learn anything new or different.

It was a good opportunity to take a look at the past and see what we’ve lost by going forward with technology.

Checking your syntax on commit

A good IDE can spot programming syntax errors and alert you to them before they ever make it into a git commit. However, sometimes when you’re in a hurry, tired, or distracted, these alerts go unnoticed and there is a greater risk that you’ll commit broken files to your git branch. Git makes it a snap to revert changes, but wouldn’t it be nicer if you could prevent it from happening in the first place?

To that end, git has a nice feature called client-side hooks. In particular, you can create a hook known as a pre-commit hook that executes right before you commit something. It gives you the option to abort if something doesn’t look right. Using this feature, I created a simple script to check PHP and Javascript syntax on commit. It’s helpful for those mornings when I haven’t quite had enough coffee yet.

Yii Javascript redirect: jsredirect

One of the platforms I have to develop for is iSites. This is a Harvard grown LMS that is complicated and annoying, but functional.

Since I have to develop tools that fit within this framework I have to work around its limitations. One of the simpler to understand limitations is the idea of not having control of the headers sent. Since by the time it gets to my tool, the page has already started loading, output has already been sent, so doing a redirect with PHP’s header function is impossible.

Yii has 2 ways to forward things through the controller. redirect and forward. Redirect uses header and forward doesn’t change the URL. So the best way to forward within isites is to use a js forward. I.e. document.location = “www.google.com”

So in the controller.php in components which extends CController I added a method jsredirect:
 https://github.com/jazahn/Quizmo/blob/ma…

	protected function jsredirect($url){
		// set the redirect in a session
		Yii::app()->session['jsredirect'] = $url;

		// forward to the jsredirect action
		$this->forward('/site/jsredirect');
	}

This just sets a session var for the redirect and forwards to site/jsredirect so in SiteController.php I have

public function actionJsredirect(){
		
		if(isset(Yii::app()->session['jsredirect'])){
			$this->render('jsredirect',array(
				'url'=>Yii::app()->session['jsredirect'],
			));
		}
		
	}

And then in the jsredirect template file we have

<script>
window.location.replace("{$url}");
</script>

Giving up on Yii Oracle Clobs

Started off yesterday with the intention of trying to implement functional Oracle Clobs in Yii similar to how I implemented it in CakePHP a couple years ago. As yesterday went on I kept busting through boundaries and was feeling great about my progress. But Then I hit the roadblock and I wasn’t able to continue. It’s not worth spending another couple days on when I have a deadline for a pilot by Fall. 4000 characters is enough for the pilot.

The result has been to alter the Yii COciSchema. Just changing the declaration of text to a varchar2(4000).

   public $columnTypes=array(
        'pk' => 'NUMBER(10) NOT NULL PRIMARY KEY',
        'string' => 'VARCHAR2(255)',
        //'text' => 'CLOB',
        'text' => 'VARCHAR2(4000)',
        'integer' => 'NUMBER(10)',
        'float' => 'NUMBER',
        'decimal' => 'NUMBER',
        'datetime' => 'TIMESTAMP',
        'timestamp' => 'TIMESTAMP',
        'time' => 'TIMESTAMP',
        'date' => 'DATE',
        'binary' => 'BLOB',
        'boolean' => 'NUMBER(1)',
		'money' => 'NUMBER(19,4)',
    );

The issue is Yii (PDO) doesn’t support LOBs well at all, so that declaration didn’t make any sense to begin with.

Yii default ORDER BY

I ran into an issue with a minor difference between Oracle and MySQL. Apparently MySQL is better about returning rows in the order they were inserted than Oracle. Now if you want to let me know it’s wrong to assume results are returned in any specific order, I know! Neither gives any guarantee on the order of results without an ORDER BY, but Oracle is semi-random.

It took me a little while to find the right way to add default items to queries. Yii uses CActiveRecords for model queries. I already had an overridden CActiveRecord class from Yii handling “getLastInsertId” with Oracle. So I knew I would be able to use that somehow.

I finally discovered scopes. It allows me to define a scope:

public function scopes()
{
    return array(
        'sort_order'=>array(
            'order'=>'SORT_ORDER ASC',
        ),
        'id_order'=>array(
            'order'=>'ID ASC',
        ),
    );
}

and then use it as such:

MyModel::model()->id_order()->FindAllByAttributes(array('SOMECOLUMN'=>1))

But still I didn’t find anything on default scopes. On a whim I did a grep -i “defaultscope” on the code and discovered it exists in the Yii framework. So I was able to piece together the following:

public function defaultScope()
{
    return array(
 	'order'=>'ID ASC'
    );
}

and bam. Add that to my QActiveRecord, and it’s golden.

Behavior Driven Development Frameworks

I’ve been going nuts integrating Behat into Yii because BDD seemed so cool. Behat actually provides a yiiextension, but I’m not proficient with phars (think php jar), so it was annoying to get it integrated with Yii.

PHPUnit_story was cool and convenient, but was deprecated in 3.5 and removed in 3.6 in favor of behat.

Upon further reading though, I made the realization that Behat is unnecessary and very much a waste of time. The developer is the only one who will be dealing directly with the unit tests, so by turning the unit tests into awkward-english is just obfuscation. It will make less sense to the person working with the code and adds a layer of work to the project.

I am not saying anything bad about BDD, but BDD doesn’t need a DSL to be BDD. The test methods can still be written for Behaviors and it will still carry with it all the BDD benefits.

RoR*’s Cucumber should also be mentioned. The RoR community seems to have really embraced the BDD framework Cucumber. It should also be noted that RoR community seems to set the trends for other framework niches. That being the case, maybe cucumbers are in everyone’s future.. but as of now, the practice has not caught on anywhere else. Behat is the least popular PHP lib I’ve ever worked with. JBehave is considered out there. Same with Python’s “Lettuce”.

* Opinion: I consider Ruby to be a hobby language. People don’t make real applications in RoR, they’re more academic with it. Which isn’t bad, I’m glad to see Java displaced as the academic language, but people actually do stuff with Java. Ruby is a fine play language, but people who do Ruby, are probably not doing anything real.

Posted in ATG, PHP, Yii. Tags: , , , , , . 2 Comments »

Using Smarty variables inside Javascript

I looked for appropriate answers for this on the smarty site, and the resounding answer was escaping javascript’s {}s with {literal}’s

Smarty template vars and Javascript functions
How to use Javascript codes in template files?
Access Smarty value with javascript

They basically all say to do something like this:

// $question_ids_json = ["1","2","3","4","5"]
{literal}
<script>
$(document).ready(function(){
	var question_ids = {/literal}{$question_ids_json}{literal};
	
	alert(question_ids[0]);

});
</script>
{/literal}

So they want to put everything in a literal tag, and then basically escape that literal tag when smarty needs to be used.

I didn’t like this, so I put the value in a hidden input and then just retrieved that input in the javascript, thereby keeping the js clean of smarty shenanigans:

<input type="hidden" id="question_ids" value='{$question_ids_json}'/>

<script>
$(document).ready(function(){
	//var question_ids = {$question_ids_json};
	var question_ids = eval($('#question_ids').val());
	
	alert(question_ids[0]);


});
</script>

But this is just a matter of personal preference.