Flextrine Tutorial – CRUD in a simple Flex 4 address book: Loading the entities

Introduction
Setting up the server
Creating the entities
Creating the database schema
Loading the entities
Creating new entities
Deleting entities
Updating entities
Conclusion

In FlashDevelop or Flash Builder create a new Flex 4 project and add the Flextrine client side library (in flextrine/src of the Flextrine download) to the classpath of your project.  Alternatively you can use the compiled flextrine/bin/flextrine.swc.  Now return to the Flextrine manager and click on GENERATE AS3 CLASSES.  You will be prompted to download a zip file – extract its contents into the src directory of your project.  You should now have AS3 versions of vo.ContactGroup and vo.Contact for use in your Flex application.

For reference, here are a few screenshot of what we will be working towards.  The tree on the left will show the groups and contacts, and the area on the right will have the group editor at the top and the contact editor below.  We will also have some buttons to create, delete and save contacts and groups.

Flextrine Contacts 1Flextrine Contacts 2

Create the Main.mxml entry class

We will begin by creating the Main.mxml entry class for our application.  To start with we will just create the basic MXML Application with a creationComplete event listener that configures Flextrine’s central class – the EntityManager.  For our simple application the only configuration that is required is to set the URL of gateway.php in the Flextrine server side component – in this case http://localhost/contacts/gateway.php.

   1: <?xml version="1.0" encoding="utf-8"?>

   2: <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   3:                xmlns:s="library://ns.adobe.com/flex/spark"

   4:                xmlns:mx="library://ns.adobe.com/flex/mx"

   5:                xmlns:local="*"

   6:                creationComplete="creationComplete()">

   7:

   8:     <fx:Script>

   9:         <![CDATA[

  10:         import org.davekeen.flextrine.orm.Configuration;

  11:         import org.davekeen.flextrine.orm.EntityManager;

  12:

  13:         private var em:EntityManager;

  14:

  15:         /**

  16:          * Initialize the Flextrine EntityManager, set the dataprovider of the tree and load the ContactGroups.

  17:          */

  18:         private function creationComplete():void {

  19:             // Setup the entity manager

  20:             var configuration:Configuration = new Configuration();

  21:             configuration.gateway = "http://localhost/contacts/gateway.php";

  22:

  23:             em = EntityManager.getInstance();

  24:             em.setConfiguration(configuration);

  25:         }

  26:

  27:         ]]>

  28:     </fx:Script>

  29:

  30: </s:Application>

Now we’ll add the GUI.  We’ll add a Flex Tree on the left with id tree, along with the buttons and the layout.

   1: <?xml version="1.0" encoding="utf-8"?>

   2: <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"

   3:                xmlns:s="library://ns.adobe.com/flex/spark"

   4:                xmlns:mx="library://ns.adobe.com/flex/mx"

   5:                xmlns:local="*"

   6:                creationComplete="creationComplete()">

   7:

   8:     <fx:Script>

   9:         <![CDATA[

  10:         import org.davekeen.flextrine.orm.Configuration;

  11:         import org.davekeen.flextrine.orm.EntityManager;

  12:

  13:         private var em:EntityManager;

  14:

  15:         /**

  16:          * Initialize the Flextrine EntityManager, set the dataprovider of the tree and load the ContactGroups.

  17:          */

  18:         private function creationComplete():void {

  19:             // Setup the entity manager

  20:             var configuration:Configuration = new Configuration();

  21:             configuration.gateway = "http://localhost/contacts/gateway.php";

  22:

  23:             em = EntityManager.getInstance();

  24:             em.setConfiguration(configuration);

  25:         }

  26:

  27:         ]]>

  28:     </fx:Script>

  29:

  30:     <s:HGroup width="100%" height="100%">

  31:         <!-- The groups and contacts tree -->

  32:         <s:VGroup height="100%">

  33:             <mx:Tree id="tree" width="100%" height="100%" />

  34:         </s:VGroup>

  35:

  36:         <s:VGroup width="100%" height="100%">

  37:             <!-- The editors will go here -->

  38:

  39:             <mx:Spacer height="100%" />

  40:

  41:             <mx:HRule width="100%" />

  42:

  43:             <!-- The buttons -->

  44:             <mx:ControlBar width="100%" horizontalAlign="center">

  45:                 <s:Button label="New group" />

  46:                 <s:Button label="New contact" />

  47:                 <s:Button label="Delete" />

  48:                 <s:Button label="Save" />

  49:             </mx:ControlBar>

  50:         </s:VGroup>

  51:     </s:HGroup>

  52:

  53:

  54: </s:Application>

Loading the contacts into the tree

Now its time to load some data into the tree.  Obviously at this point there isn’t any data to load so for the moment we’ll manually add some into the database so we have something to see.  Execute the following SQL against the contacts database to create some test data.  This creates two groups and three contacts, just like in the screenshots at the top of this section.

   1: INSERT INTO `contact` (`id`,`name`,`telephoneNumber`,`birthday`,`contactGroup_id`) VALUES

   2:  (1,'Arthur','01332 823636','1976-01-12',2),

   3:  (2,'Mum','07884 763623','1976-01-13',1),

   4:  (3,'Peter','0131 827 3625','1977-12-06',2);

   5:

   6: INSERT INTO `contactgroup` (`id`,`name`) VALUES

   7:  (1,'Family'),

   8:  (2,'Friends');

At this point we should talk about the concept of Flextrine’s entity repositories.  Every entity in your application has its own EntityRepository, so for our application we have one EntityRepository for ContactGroup and one for Contact.  Entity repositories perform a number of functions:

  • First and foremost entity repositories provide local storage for your entities.  Each EntityRepository has an attribute called entities which is an ArrayCollection containing the entities currently in existence in your application.
  • Secondly entity repositories make sure that there is only ever one instance of a particular entity in existence at any one time.
  • Finally entity repositories watch their entities for changes and mark them for updating when they change.

Add the following lines to the end of creationComplete() remembering to add import vo.ContactGroup to the top of the script tag.

   1: tree.dataProvider = em.getRepository(ContactGroup).entities;

   2: em.getRepository(ContactGroup).loadAll();

The first line sets the entities of the ContactGroup EntityRepository as the dataProvider of the tree.  Obviously at this point there are no entities in the ContactGroup repository, but Flextrine is very careful to respect Flex databinding throughout its lifecycle so in fact it doesn’t matter that entities is currently empty.  Any Flex component bound to the entities will automatically update themselves when the repository changes with no extra work required.

The second line calls the loadAll() method on the ContactGroup repository.  As you would expect this loads all the ContactGroups into the ContactsGroup repository and Flex databinding will take care of updating the tree once the load is complete.  By default Flextrine runs in EAGER mode, which means that when loading entities it will follow all associations and load any linked objects, so in fact loading the ContactGroups will also load all the Contacts.  Flextrine also supports LAZY loading which won’t automatically follow associations and requires you to to explicitly request unitialized entities; see Loading Associations for more details.

If you now run the application it will look like this.

Flextrine Contacts 3

We can see that the two ContactGroups are loading from the database and that Flex databinding has updated the tree automatically to reflect the loaded entities.  Unfortunately the tree doesn’t realise that it should be showing contacts as children of the contact groups, so we need to explicitly tell it so by adding a children attribute to ContactGroup.  Flextrine allows you to add logic to your entities by seperating Flextrine specific code into an ‘EntityBase’ class, and then creating an empty main entity class which you can ammend.  The idea behind this is that if you later update your entities you can replace the EntityBase without losing any functionality you added to the main entity class.

Open up vo/ContactGroup.as and add a getter function that simply returns the contacts:

   1: package vo {

   2:     import mx.collections.ArrayCollection;

   3:

   4:     [RemoteClass(alias="vo/ContactGroup")]

   5:     [Entity]

   6:     public class ContactGroup extends ContactGroupEntityBase {

   7:

   8:         public function get children():ArrayCollection {

   9:             return contacts;

  10:         }

  11:

  12:     }

  13:

  14: }

We also want the labels in the tree to show the name property of both ContactGroup and Contact so add labelField=”name” to the Tree component in Main.mxml:

   1: <mx:Tree id="tree" width="100%" height="100%" labelField="name" />

Now running the application should show the following!

contacts4

Lets see how we can create new entities.

Flextrine Tutorial – CRUD in a simple Flex 4 address book: Creating the database schema

Introduction
Setting up the server
Creating the entities
Creating the database schema
Loading the entities
Creating new entities
Deleting entities
Updating entities
Conclusion

Once we have defined the entities in the entities directory of the Flextrine server component it is very simple to create the appropriate database schema.

Creating the database schema

Browse to http://localhost/flextrinemanager (or whatever URL you pointed to the manager directory).  You should see a screen like this:

Flextrine Manager 1

Enter the URL of the Flextrine server side component (http://localhost/contacts) in the FLEXTRINE PROJECT URL input and Click to refresh.  The Flextrine manager will examine your project and update the manager to show the entities and database.  Now click on Create schema to automatically generate the appropriate tables in the database.  The manager should now look like this:

Flextrine Manager 2

Under the hood Doctrine 2 has parsed the annotations in ContactGroup and Contact and has determined the appropriate tables and columns that will be required to persist the objects.  Although you will never need to edit the schema manually, the following SQL is what was actually executed when you clicked CREATE SCHEMA.  Notice that Doctrine enforces referential integrity through MySQL constraints so that, for example, you cannot delete a ContactGroup which has any Contacts referring to it.

   1: CREATE TABLE  `contact`.`contactgroup` (

   2:   `id` int(11) NOT NULL AUTO_INCREMENT,

   3:   `name` varchar(100) NOT NULL,

   4:   PRIMARY KEY (`id`)

   5: );

   6:

   7: CREATE TABLE  `contact`.`contact` (

   8:   `id` int(11) NOT NULL AUTO_INCREMENT,

   9:   `name` varchar(80) NOT NULL,

  10:   `telephoneNumber` varchar(50) DEFAULT NULL,

  11:   `birthday` date DEFAULT NULL,

  12:   `contactGroup_id` int(11) DEFAULT NULL,

  13:   PRIMARY KEY (`id`),

  14:   KEY `contactGroup_id` (`contactGroup_id`),

  15:   CONSTRAINT `contact_ibfk_1` FOREIGN KEY (`contactGroup_id`) REFERENCES `contactgroup` (`id`)

  16: );

Now that the schema has been created you can use UPDATE SCHEMA whenever you add/remove entities or attributes within entities to update the schema without losing any data that is already in the database.  This gives you a very efficient workflow as your entities expand over the lifetime of a project.

We now have everything we need in the Flextrine server side component and in the database.  Its time to start writing some Flex code!

Flextrine Tutorial – CRUD in a simple Flex 4 address book: Setting up the server

Introduction
Setting up the server
Creating the entities
Creating the database schema
Loading the entities
Creating new entities
Deleting entities
Updating entities
Conclusion

Before using Flextrine you need to do some groundwork to get your project ready.

  1. Download the latest version of Flextrine from http://code.google.com/p/flextrine2/downloads/list
  2. Install the Flextrine manager.  This is as simple as copying the manager directory from the Flextrine download into a web-accessible directory.  For the purposes of the tutorial I will assume that you have set the URL pointing at this document root as http://localhost/flextrinemanager.  Note that you will require mod_rewrite to be enabled on your webserver for the manager to function correctly.
  3. Install the Flextrine server side libraries.  These are contained in the flextrine/web/lib directory of the the Flextrine download.  All you need to do to install these is to copy flextrine/web/lib to a directory in your PHP include_path, or ammend the include_path to include the flextrine/web/lib directory.  Note that if you don’t want to change your include_path you can set it explicitly after the next step by uncommenting the $flextrineIncludePAth line in config.php of your project (see http://code.google.com/p/flextrine2/wiki/GettingStarted for more details).
  4. Install the latest version of Doctrine 2 from http://www.doctrine-project.org/projects/orm/download.  Doctrine 2 is the technology that Flextrine is based upon and required for its operation.  The easiest way to install Doctrine is to merely extract the package into flextrine/web/lib as this is already in your PHP include_path.  Alternatively you can add a new entry to your include_path pointing to Doctrine.
  5. Create an empty server-side Flextrine project.  The Flextrine download contains a blank project in flextrine/web/flextrineproject which will be your starting point.  Copy this to a new directory on your machine and make this directory web accessible.  For the purposes of this tutorial I will assume that you have set the URL pointing to this directory as http://localhost/contacts and will refer to the directory as the Flextrine server side component.
  6. Create a new MySQL database called contacts.
  7. In your Flextrine server side component open up config.php and set the database connection options in the $connectionOptions variable.

Note that next time you start a new Flextrine projects you only need to do steps 5 – 6 as steps 1 – 4 only need to be done once.

Now we are ready to use Flextrine!  The next step is to create some entities.