BaseObject

I was talk­ing about it, here it is!

This class will come in handy every time you work with syn­chro­nous SQLite data­bases in an AIR project. It’s a real-world imple­men­ta­tion of the Dynam.ize util­ity I pre­sented ear­lier… I will show you an exam­ple of how to work with it, with sim­ple sub-classes. Let’s go!

First things first.

I need to open my data­base and pro­vide that con­nec­tion to BaseObect:

var sqlCon:SQLConnection=new SQLConnection();
sqlCon.open(File.applicationDirectory.resolvePath('data.sqlite'));
BaseObject.defaultConnection=sqlCon;

We need clients!

Now, let’s con­sider a data­base with a “client” table (pretty cre­ative, right?), those clients have a name, a URL and a gen­der (male/female), and of course, an ID. So we have a “client” table with 4 fields: id, name, url, male (which is a Boolean: true=male, false=female).

I have mapped a BaseOb­ject sub-class to this table (I will show you how in a few moments), so I can now cre­ate a new client in a pretty sim­ple fashion:

var myClient:Client=Client.create({name:'Joe', url:'http://www.yep.com', male:true});

Cool, I now have a Client instance I can work with and a line has been added in my “client” table. What if I wanted to change its name? Easy.

myClient.setName('Mark');

The “name” field has been updated. Let’s check that.

trace(myClient.getName());

Traces “Mark”? Good. OK, what about updat­ing the URL and name at the same time? Two queries? Nope!

myClient.update({name:'Jack', url:'http://www.yo.net'});

Now let’s grab a client via his ID.

var c1:Client=Client.getFromID(1);

Sim­ple. But what if I wanted to grab more than one client, fox exam­ple what if I wanted all male clients?

var males:Array=Client.getFromQuery('SELECT * FROM client WHERE male=@male', {'@male':true});

You can now loop through this array and inter­act with the Client instances it contains…

What’s the trick?

Noth­ing too hard to under­stand. Client is a sub-class of BaseOb­ject that sim­ply exposes some of its sta­tic and instance meth­ods (get­Fro­mID, get­From­Query, cre­ate, update and so on). It also casts BaseOb­ject return val­ues to the right type: Client. For exam­ple, this is how get­Fro­mID works:

public static function getFromID(id:uint):Client {
	return BaseObject._getFromID(getTableData(), id) as Client;
}

Now you might won­der what this get­Table­Data method is. Well it returns data about the table to which Client is bound to, like that:

public static function getTableData():TableData {
	if (!_tableData) _tableData=new TableData('client', Client, ['name', 'url', 'male']);
	return _tableData;
}

See? We define the table name (client), the cur­rent class (Client) and the fields we need to han­dle (name, url and male)… That’s it.

Our clients bought cars…

That’s right, so we should have a “car” table, right? With id, name, brand, cli­en­tID and pur­chase­Date we should be good. Its Table­Data would look like that:

 new TableData('car', Car, ['name', 'brand', 'clientID', 'purchaseDate']);

Note: I didn’t list id as BaseOb­ject sup­poses there’s always an id field.

OK, so our clients bought cars, and we’d like to know who bought what. Let’s write a method in Client to do that:

public function getCars():Array {
	return Car.getFromQuery('SELECT * FROM car WHERE clientID=@id', {'@id':id}));
}

That works, cool. But we can do bet­ter, we could cache this Array so we don’t query every time we need it ; there’s a tech­nique for that:

public function getCars(force:Boolean=false):Array {
	return (hasCache('cars') && !force) ?
		getCache('cars') :
		setCache('cars', Car.getFromQuery('SELECT * FROM car WHERE clientID=@id', {'@id':id}));
}

Done. Opti­mized.

We can now see which cars our first client bought:

var c1cars:Array=c1.getCars();

We could also imple­ment the oppo­site: retriev­ing a Client form a Car instance:

public function getClient():Client {
	return Client.getFromID(this.getClientID());
}

Notice how I used get­Cli­en­tID? This refers to the table’s cli­en­tID field and returns it.

That’s a wrap.

Well that’s pretty much it, I think I cov­ered the basics!

If you want to play with it, get the class/demo project and tell me what you think. I’ve bun­dled Client, Car and some exam­ple uses…

Dynam.ize

Still while work­ing on this app I was talk­ing about ear­lier I real­ized I was quite used to work­ing with PHP classes’ Magic Meth­ods, and more pre­cisely the way it han­dles over­load­ing. Those lovely __get, __set and __call meth­ods are called when­ever you try to access a property/method that is not explic­itly defined, mak­ing your class dynamic. Of course you don’t need this all the time, and it might even be dan­ger­ous, but it some cases that’s sim­ply perfect.

You can do that with AS3 if you extend flash.utils.Proxy, cool. But wait, no! Not cool! What if I wanted to extend some­thing else? Nah, let’s find some­thing else…

I came up with the idea of dynam­i­cally cre­at­ing get­ter and set­ter func­tions on a class instance for pre­de­fined properties. Now those aren’t really get­ters and set­ters but let me show you what it looks like so you under­stand bet­ter… Here’s an example:

package {
	import net.tw.util.Dynam;
	// This is my class, that has to be dynamic
	public dynamic class DynClass {
		// This Array will be used to store the properties' values...
		protected var _data:Array=[];
		public function DynClass() {
			// In the constructor I call the Dynam.ize method on this, so it builds the getters and setters for the supplied properties
			Dynam.ize(this, ['abc', 'def', 'ghi'], getter, setter);
		}
		// Here are the functions that will be called when I try to get or set one of the properties I listed in Dynam.ize
		protected function getter(key:String):* {
			return _data[key];
		}
		protected function setter(key:String, v:*):void {
			_data[key]=v;
		}
	}
}

Now let’s instan­ti­ate this class and play with it:

var dc:DynClass=new DynClass();

We can call getAbc() or setAbc() on it:

dc.setAbc('my value');
trace('get abc', dc.getAbc());

Every­thing should be OK. It would work the same with get/setDef and get/setGhi… This exam­ple might not seem very use­ful but you could do any­thing within the get­ters and set­ters ; for exam­ple access Share­dOb­jects, send­ing data to a server and so on…

Find the class and a demo project on as3-bits!

Com­ing up next: my imple­men­ta­tion of this con­cept for AIR’s SQLite databases!

Thoughts?

Flex — GradientLabel

If you’ve ever won­dered whether it’s pos­si­ble to apply a gra­di­ent on a Flex Label, well it is ; but that’s not very straight for­ward… As I’m work­ing on a app that requires this kind of glit­ter I decided to try and see what could be done.

I started with a basic Action­Script project (no Flex involved) and came up with this. Quite func­tional, could prob­a­bly be opti­mized but my goal was actu­ally a Flex com­po­nent and I knew that was tech­ni­cally fea­si­ble. I then sim­ply extended Flex’s Label class and basi­cally copied/pasted the logic into it. Just had to fig­ure out which event to lis­ten to and I was good to go…

Here’s a demo app for your play­ing pleasure.

Go get Flash!

You may notice that in this exam­ple I embed the font so it looks nicer, but this is not mandatory…

All this is open­source (class+project) and you can grab it at my brand new Google Code dump: as3-bits. Help yourself.

As always, feed­back welcome.