The TextMate Super Function (AS3/PHP)

Following my obsession with TextMate snippets and commands, I created a function snippet which extended the basic function and added a few new useful features. This snippet is mapped to Shift + Enter. Just type the name of your function...

myFunction

and hit Shift + Enter after it. The following snippet is inserted:

/**
 *
 *
 * @return
 */
public function myFunction()
{

}

The first tab stop is inside the parentheses so you can add some parameters, hit tab again to focus on the scope (public). We use a simple regular expression here to add "_" or "__" to the method name depending on if you type public|private|protected. The rest of the tabs go through the return statement, docblock and finally end inside the function declaration.

I've got both an AS3 and PHP version. Starting with the PHP version:

cat <<SNIPPET
/**
 * $4
 *
 * @return $3
 */
${2:public} function ${2/(private)|(protected)|(.+)/(?1:__)(?2:_)(?3:)/}${TM_SELECTED_TEXT:-$TM_CURRENT_WORD}($1)
{
	$0
}
SNIPPET

And the AS3 version is basically the same with just a return type defined:

cat <<SNIPPET
/**
 * $4
 *
 * @return ${5:$2}
 */
${3:public} function ${3/(private)|(protected)|(.+)/(?1:__)(?2:_)(?3:)/}${TM_SELECTED_TEXT:-$TM_CURRENT_WORD}($1):${2:void}
{
	$0${2/void$|(.+)/(?1:return null;)/}
}
SNIPPET

I'd also like to eventually add @param docs to the docblock as you type out parameters. Would love some suggestions there.

You can download both the PHP and AS3 Function Commands here. You can also download my TextMate theme Plum Dumb, or—if you're into PureMVC—you can download my PureMVC TextMate templates.

December 29th, 2010 | Permalink

Street Ceelo: Fun Times with the iPhone SDK

Do you follow me on Twitter? You don't? Well you should! If you do though you know how much pain the iPhone SDK has brought me in the last three or four months. I'm very close to being done with a very cool app, but some Apple bugs are making it quite difficult to get it done. Care to read my story and learn about the iPhone application I'm making? Okay...

ceelo1 ceelo3

The Street Ceelo App

I'm working on a dice game – a street dice game called Ceelo. The application itself is essentially a 3D dice rolling simulation. You can play with one phone, passing it back and forth, or you can connect using iOS's GameKit over bluetooth or wi-fi and play with multiple "iDevices". It features custom UI design and elements, networking, peer to peer gameplay, animation, navigation and tab controllers...basically "the works" of the iOS kit. I used this application as a learning exercise and it's turned into an application I'm very proud of.

Pretty cool huh? Well, it was cool until iOS 4.0 came out. You see, 4.0 introduced some new classes called GameCenter that expand on GameKit. It also broke the hell out of the original GameKit classes. So my application runs "flawlessly" (it's essentially complete) on devices running the iOS versions 3.0–3.1.3, but on 4.0.X there are numerous issues with the GameKit in Apple's underlying SDK and in certain places it crashes. This is not acceptable to me so I am working to rewrite much of the code and some of the user experience itself to accommodate the issues.

The Broken

So, what broke when 4.0 was released? Here's an example. In Ceelo, there's a custom peer to peer table display. One player (server) says they are going to start a game and others (clients) join her. Now, if a client quits at any time, a "message" is send to their peers that they disconnected. No problem; we simply remove them from the list of players (if in the game lobby) or the game ends. This works fantastically in 3.x iOS. Now, in 4.0.x, instead of a quick notification, there's a lengthy delay when a player disconnects or cancels a connection request. When the message is finally "sent" (it isn't really), it crashes the server:

Thread 3 Crashed:
0   GameKitServices                 0x06352f90 gckSessionChangeStateCList + 411
1   GameKitServices                 0x0635b49c gckSessionRecvProc + 1474
2   libSystem.B.dylib               0x981c181d _pthread_start + 345
3   libSystem.B.dylib               0x981c16a2 thread_start + 34

For more information on this crash check out my StackOverflow question on the topic or poke into the developer forums. Radar IDs for these issues include 8095838 & 8203566, 8174249 & 8094858.

So I filed a bug with Apple and it's been confirmed as a "known issue". The great thing is that the recent betas of the SDK fix the crashing. Unfortunately the long delays remain. I'm continuing to file a bug with each release of the beta. I'm really shocked that this hasn't been addressed yet as the 4.1 release is supposed to be the GameCenter/GameKit release. Classic Apple though to release broken product to get it to market. It is what it is and I've learned to be patient with them in becoming an "Objective-C developer". Also, from what I understand, the 3.0 release was very much the same way.

The Fixes

At this point I'm changing some of the connection logic to remove some of the opportunities for players to quit the game. I've also changed the peer to peer game selection interface to just auto-accept incoming connection requests. This was thanks to a brilliant suggestion by Avi Itskovich who diagnosed a similar GameKit bug via my Stackoverflow post on the topic. It seems to work much better if you connect people up first.

If the game ever gets to the store, it'll be interesting to see how I'll word the required iOS version. You see, this game will work on *all* iDevices, even those without Bluetooth (I wrote it so there's wifi fallbacks). It works on iPhone, 3G, 3GS, Touches, etc. From iOS 3.0–3.1.3. It'll probably run very well on iPhone4 with 4.1 when that is released (already upscaled all the graphics for the retina display!). The only OS it won't run well on is 4.0. How should I word that? "We don't support 4.0 at all but everything else is grand". Just seems odd to have support for everything all the way back to 3.0, but here in the middle is this turd. Such is life.

That's Nice...

So what's the point of all this? Well, I'm worried that GameKit may be phased out. It doesn't seem like Apple is putting priority on fixing it and is focusing more on the Xbox Live-like GameCenter (which obviously is much more lucrative prospect than peer-to-peer gaming). So, I wanted to share my experience as an introduction to Typeoneerror Studios offering iOS development one of our new services. As frustrating as this has been, I absolutely love the Apple development kits, tools and the overall process.

Want to beta test at some point?

Send an email to ceelo at typeonerror with your device ID. How do you get that? Use this fantastic video that Sam Vermette hosts at http://whatsmyudid.com/.

August 24th, 2010 | Permalink

Permanent Facebook Sessions and Posting as a Page

For a current project, we are integrating a site with Facebook Connect and linking users of our T1EOS (our Content Management System) to their accounts. When administrators create content, the CMS publishes the article to their brand page directly from the CMS behind the scenes. This was a bit tricky to figure out how to accomplish (wasn't sure it was possible at first) given that the Facebook API had pretty much completely changed from the last time I used it; Facebook now uses OAuth 2.0 for authentication and authorization. So this article then will be an overview of how to get a permanent session (or access_token as it's called on Facebook) that will allow you to post to your fan page as the page (and not your user account).

To start, you must be an adminstrator of the page you want to post as. We're going to essentially be posting from the Application to the Page, but to post from a Facebook Application, you must give the application permission to post to your wall and also permission for offline access. In our case, offline access allows the CMS to process and post content even when I am not logged in. Once you've give permission for the application to post for you, it should be able to post to any pages you are a full administrator of. When you do it like this the post will appear as written if by the page, not your user account.

Luckily the client I am working for was gracious enough to mark me an administrator of their page, but I first tested with Typeoneerror's Fan Page. Go to your own fan page and note the ID in the url for later (hint: it comes after ?id=).

Next, you need to create a Facebook Application. If you haven't yet, you'll need to install the Facebook Developer application. Create an application and give it a name. Note your API Key, Application ID, and Application Secret. The only other thing you should need to change is your Connect URL and Base Domain. Let's just say for example's sake that we'll use http://mydomain.dev/ and mydomain.dev respectively.

Next, you need to authorize your application with some extended permissions. This is quite simple, just point a browser to the following URL, replacing {CLIENT_ID} with your Application ID and {YOUR_DOMAIN} with your Connect URL (note that your URL must have a trailing slash or it may error):

https://graph.facebook.com/oauth/authorize?client_id={CLIENT_ID}&scope=offline_access,publish_stream,create_event,rsvp_event,sms,manage_pages&redirect_uri={YOUR_DOMAIN}

Note the scope parameter. Here we are sending the extended permissions the app wants. If this is your first time authenticating, you'll see a nicely designed window explaining what the app is requesting access to. For our purposes, all we need is offline_access and publish_stream. Offline access will give us a permanent access key, allowing us to make calls to the API without being logged in or authenticated. Publish stream allows the app to, well, publish to your streams.

After you authenticate, you'll be redirected back to YOUR_DOMAIN but now you'll see a query param added to the URL which will look something like:

http://mydomain.dev/?code=1234567890abcdef.

The actual code will be much longer ;) Note it down for later. This is our authentication code that will allow us to get a permanent key. This is not the permanent key quite yet. So how do we get the permanent key? Request one from the access_token service:

https://graph.facebook.com/oauth/access_token?client_id={CLIENT_ID}&redirect_uri={YOU_DOMAIN}&client_secret={APPLICATION_SECRET}&code={YOUR_CODE}

Fire off a cURL request to the above URL, replacing {CLIENT_ID} with your Application ID, {YOUR_DOMAIN} with your Connect URL (make sure it has a trailing slash), {APPLICATION_SECRET} with your Application's Secret Key and {YOUR_CODE} with the code from the previous step. The result should be simply a piece of text that looks like this:

access_token=1234567890abcdef.

Your permanent session access token! Hooray. So let's use it. I'm using the Zend Framework so you'll see some logging includes in this code. You can ignore them. Please read the comments as I noted some tutorial notes in there. Here's the PHP snippet I wrote to post to my Page's wall from an external website. With luck, change the settings noted below and a post will appear on your page's wall too!

require_once "../library/Typeoneerror/Facebook/Library/facebook.php";
require_once "../library/Zend/Debug.php";

// need to turn these options off otherwise
// you will get errors from the API
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYHOST] = 0;
Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYPEER] = 0;

// Replace with your page's ID
$pageId = "YOUR_PAGE_ID";
// Replace with your permanent session key from the last step
$permSess = "YOUR_PERMANENT_ACCESS_KEY";

// create the Facebook API
$facebook = new Facebook(array(
"appId" => "YOUR_APPLICATION_ID",
"secret" => "YOUR_APPLICATION_SECRET",
"cookie" => true,
));

// should log out your page's info.
// simply makes a call to the Graph API
// you don't need a session for this.
$page = $facebook->api("/{$pageId}");
Zend_Debug::dump($page);

// publish to the page
// you do need a session for this.
$rest = $facebook->api(array(
"uid" => $pageId,
"method" => "stream.publish",
"access_token" => $permSess,
"message" => "This is a test. Experimentation with OAuth and permanent sessions on Facebook.",
));

// should log an ID of a created wall post
Zend_Debug::dump($rest);

Did you like this article? Maybe you'll like our company page:

June 29th, 2010 | Permalink

Getting Started with Custom Zend_Tool Resources

Recent versions of the Zend Framework come with a useful CLI (command line) tool for manipulating project structure and files called Zend_Tool. Assuming you use a standard framework layout, this tool can speed development by creating controllers, views, models, et al. I found this tool useful, but wanted to extends the tool to make it more custom to my liking. i.e. instead of

zf create controller Articles

outputting a controller that extends Zend_Controller_Action, I want to make a CMS controller builder; one that extends Typeoneerror_Cms_Controller_Crud, sets and creates a model that extends Typeoneerror_Db_ActiveRecord, etc. My intention at the beginning of this was to add a Provider that allowed me to type

zf create crud Articles

and set up all of this. After spending a few hours figuring out where everything was and how it worked, it's pretty clear that ZF Tool is still very much a "baby." Set-up is quite challenging, and you have to write quite a bit of code to make your own providers (providers define your command line actions) and contexts (contexts define resources and how to handle provider actions).  I thought I'd provide some basic steps to get started with your own resources.


Installing the zf tool.

First thing you need to do is install the zf.sh script. This is available in the "bin" directory of the release. I've got my own library with a subversion external to the latest release checked out in it, so I copied the "bin" file into the same directory. So locally I have something like:

/typeoneerror
    /bin
        /zf.php
        /zf.sh
    /library
        /Typeoneerror
        /Zend

Now, the zf scripts need to be in your unix include_path to run. Instead of doing that I added an alias to my .bash_profle that points to the shell script:

alias zf='/Users/ben/Documents/Codebase/taz/trunk/project/bin/zf.sh'

Also, make sure the zf script is executable:

chmod a+x /Users/ben/Documents/Codebase/taz/trunk/project/bin/zf.sh

Now if you run the following command, you should see the version output:

$ zf show version
Zend Framework Version: 1.10.2

In recent versions of zf tool, you have to create a storage directory and configuration file if you want to write any custom contexts or providers. Let's do that next. First run:

$ zf --setup storage-directory
Storage directory created at /Users/ben/.zf/

followed by:

$ zf --setup config-file
Config file written to /Users/ben/.zf.ini

If you open that up you should see that the include path to the Zend library folder has been added because it's where the zf script expects it to be ("../library"). Since my client code in Typeoneerror directory lives there as well, we should be set.

# Inside /Users/ben/.zf.ini
php.include_path = "/Users/ben/Documents/Codebase/taz/trunk/project/library:.:"


Custom Resources

Now, to begin creating custom providers, we first need a Manifest. A custom manifest tells the tool what providers to register. Let's create a manifest and a sample provider first:

# Manifest.php

require_once "Typeoneerror/Tool/Provider/Crud.php";

class Typeoneerror_Tool_Manifest implements Zend_Tool_Framework_Manifest_ProviderManifestable
{
    public function getProviders()
    {
        return array(
            new Typeoneerror_Tool_Provider_Crud()
        );
    }
}

All we implement in this file is the getProviders method which returns a list of instantiated providers.

# Crud.php

class Typeoneerror_Tool_Provider_Crud
extends Zend_Tool_Project_Provider_Abstract
implements Zend_Tool_Framework_Provider_Pretendable
{
    public function create($name = 'world')
    {
       $this->_registry->getResponse()
                       ->appendContent("Hello, {$name}!");
    }
}

Our sample defines a create method which simply echos out a "Hello" message
to the CLI output. Before you can actually use these new tools though, we
have to register them with the Reposity. Back to the command line:

$ zf enable config.manifest Typeoneerror_Tool_Manifest
Provider/Manifest 'Typeoneerror_Tool_Manifest' was enabled for usage with Zend Tool.

If you take another look at your config file you'll see something like:

php.include_path = "/Users/ben/Documents/Codebase/taz/trunk/project/library:.:"
basicloader.classes.0 = "Typeoneerror_Tool_Manifest"

Next register the Crud provider:

trunk $ zf enable config.provider Typeoneerror_Tool_Provider_Crud
Provider/Manifest 'Typeoneerror_Tool_Provider_Crud' was enabled for usage with Zend Tool.

And check the ini output again

php.include_path = "/Users/ben/Documents/Codebase/taz/trunk/project/library:.:"
basicloader.classes.0 = "Typeoneerror_Tool_Manifest"
basicloader.classes.1 = "Typeoneerror_Tool_Provider_Crud"

This tells the tool to load those classes for use. Theoretically, you could just add these manually to the ini file. Anyway, now we can run our tool!

$ zf create crud
Hello, world!

$ zf create crud Ben
Hello, Ben!

If you run the following you can now see that the Crud controller is registered
with the zf tool.

$ zf show manifest
type=Tool, clientName=all, providerName=Crud    : crud


Custom Output Providers and Contexts

Ok, great, now we can see how to register parts with the zf tool, but now you're wondering (probably)
"how do I create custom output?".

Well, you're going to need to create two classes: a Context (in most cases a "file context" or how to save the file and the code that will be injected into the file) and a Provider which is initialized from the CLI and uses Contexts to create the resources. I found this tutorial to be a good overview of those steps.

To make things easy for my crud controller provider, I simply copied Zend_Tool_Project_Context_Zf_ControllerFile (context) and Zend_Tool_Project_Provider_Controller (provider) and edited the code generation to suit my needs. You can download the sample files I created here. The Provider defines the "create" and "delete" functions which are accessed from the command line. The Provider checks to see if the Crud controller exists and if not, creates it using Zend_CodeGenerator (Typeoneerror_Tool_Context_CrudControllerFile :: getContents).

As I said at the beginning, custom output is a chore, but I feel like this has a load of potential. ZF 1.10 begins the support of "delete" methods with providers as well but they don't seem to be fully complete yet (I implemented a delete method in my crud provider but I'm unsure how to remove the line item in the .zfproject.xml manifest as of yet). You may find yourself manually editing your project manifest as you get going.

Good luck! Feel free to send me a message if you have any tips or questions about Zend_Tool.

March 7th, 2010 | Permalink

PHPUnit Follow-up: Code Coverage with Xdebug on Mac

It took me considerable amount of time to figure out the correct file to edit in order to have Xdebug work from the command line with PHPUnit's --report flag. This flag generates HTML files that look something like the following image:

code coverage of ASRA 2.0 with Xdebug

This displays the number of lines that have been run in the process of unit testing; and in a lovely readable format (see Xdebug's normal format to see how much more useful this is). To get PHPUnit and Xdebug working, start by following the tutorial in the previous article. Then to get Xdebug running, check out this post by Felx Geisendörfer. Follow steps 1 + 2. If you are using regular-old MAMP, 3 + 4 should get you going just fine. The problem I had was I am using MAMP Pro, so I was editing my "template" .ini file thinking that was where the lines needed to go. Xdebug was loaded as a browser module, but was not loaded when I ran the coverage report in PHPUnit. So, in Pro, you have to add the config options to /Applications/MAMP/conf/php5. This is the ini file that the CLI version of PHP uses.

Here are the lines I added to get it working. Note that you may also need to disable the ZendExtensionManager and the zend_optimizer extension for it to work..in MAMP just uncheck the box. Check the compatibility section on the install page for more.

[Zend]
;zend_optimizer.optimization_level=15
;zend_extension_manager.optimizer=/Applications/MAMP/bin/php5/zend/lib/Optimizer-3.3.3
;zend_optimizer.version=3.3.3
;zend_extension=/Applications/MAMP/bin/php5/zend/lib/ZendExtensionManager.so

[xdebug]
zend_extension=/Applications/MAMP/bin/php5/lib/php/extensions/no-debug-non-zts-20050922/xdebug.so
xdebug.remote_enable = 1

If you completed the other article, PHPUnit should be using MAMP's php, which should now have Xdebug rocking and you can do something like:

# 'report' is the name of the folder the html will output to
$ phpunit --report report My_Test 
November 15th, 2009 | Permalink
prev 1 2 3 next