Now that we have a spiffy new installation of QCubed, it is time see what it can do. In this section, we will take a look at the backbone of Qcubed, code generation. Here we will create a database, configure QCubed for the generation, generate the code, and explain what files are created. What we will not do is your laundry. Stop asking.
Qcubed supports a few databases; for this purpose, I will be using MySQL.
Before we can generate anything, we need to have a database set up. Lucky for you, I happen to have some sql for one right here. It is small database describing people, their phone numbers and hobbies. Probably the single most useful database known to man. Or not. What it will do though is help illustrate some of the features of QCubed code generation. So create this database:
CREATE DATABASE `project`; USE project; CREATE TABLE `hobby` ( `name` varchar(45) NOT NULL, PRIMARY KEY (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE `number_type` ( `id` int(10) unsigned NOT NULL auto_increment, `name` varchar(45) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `Index_2` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ; INSERT INTO `number_type` (`id`, `name`) VALUES (1, 'Home'); INSERT INTO `number_type` (`id`, `name`) VALUES (3, 'Mobile'); INSERT INTO `number_type` (`id`, `name`) VALUES (2, 'Office'); CREATE TABLE `person` ( `id` int(10) unsigned NOT NULL auto_increment, `name` varchar(45) NOT NULL, `age` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `Index_2` (`age`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; CREATE TABLE `person_hobby_assn` ( `person_id` int(10) unsigned NOT NULL auto_increment, `hobby_name` varchar(45) NOT NULL, PRIMARY KEY USING BTREE (`person_id`,`hobby_name`), KEY `FK_person_hobby_assn_3` USING BTREE (`hobby_name`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; CREATE TABLE `telephone` ( `id` int(10) unsigned NOT NULL auto_increment, `number` varchar(10) NOT NULL, `type` int(10) unsigned NOT NULL, `person_id` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `FK_telephone_1` (`type`), KEY `FK_telephone_2` (`person_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; ALTER TABLE `person_hobby_assn` ADD CONSTRAINT `FK_person_hobby_assn_3` FOREIGN KEY (`hobby_name`) REFERENCES `hobby` (`name`), ADD CONSTRAINT `FK_person_hobby_assn_2` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`); ALTER TABLE `telephone` ADD CONSTRAINT `FK_telephone_1` FOREIGN KEY (`type`) REFERENCES `number_type` (`id`), ADD CONSTRAINT `FK_telephone_2` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION;
As you can see, my database is InnoDB and uses foreign keys. There are also some special tables that we will get to later. You don't have to use foreign keys in your database, but as you will soon see, it makes for some nifty code generation!*
After you create your database, you will need to tell Qcubed which database to use as well as the username and password to access it. You do this within the configuration.inc.php file. Look for lines such as:
define('DB_CONNECTION_1', serialize(array( 'adapter' => 'MySqli5', 'server' => 'localhost', 'port' => null, 'database' => '', 'username' => 'root', 'password' => '', 'profiling' => false)));
Notice that the adapter is MySqli5. "I only have the MySql exstention and I don't have the rights to change it!" you cry. Don't cry. Just change the adapter to 'MySql.' And then hound your admin to enable MySqli5. After this, you will need to put the database name, username, and password within the appropriate quotes.
Now we just need to start with the generating! Navigate your browser to the start page of your project. The first link on this page is for the code generation. It should be <your project name>/_devtools/codegen.php. Go ahead and click it. Click it like you mean it. (NOTE: There is a bug in QCubed 1.1.2 and 2.0.1 that prevents the association table GUI from working correctly. Please apply http://trac.qcu.be/projects/qcubed/attachment/ticket/623/ticket623v2.patch if necessary.)
Give it a few seconds as it works the magic. If everything was done correctly, you should see a code generator page with XML settings and the results. The results should be:
There were 4 tables available to attempt code generation: Successfully generated DB ORM Class: Hobby (with 1 relationship) Successfully generated DB ORM Class: Person (with 1 relationship) Successfully generated DB ORM Class: Telephone (with 2 relationships) Successfully generated DB Type Class: NumberType
One thing you may notice right away is that although there are five tables, only 4 table classes were made. The person_hobby_assn table does, as a relationship table, does not get a class. Instead, as we will see in more depth in the next chapter, it is referenced through the classes that use it, person and hobby.
So what really happened here? What mystical forces were unleashed by this generation? Well, let's take a look. To the file system!
There are quite a few files created. First, inside the drafts folder of your project, you will find many new files and a folder called dashboard. These files create forms that allow you to edit your tables. They are an excellent starting point for creating your project. In fact, in some cases, you may find that they are enough entirely. As can be seen, each table has gotten four files. One file lists all the records for that table. Another is used to edit a record. The other two files are template files. The files inside the dashboard folder perform the same task as these files. The difference is that the dashboard does its editing using an Ajax technique. Which you use is up to you. But all files are great places to examine the basic structure of QForms put to actual practice. If you want to take a look at the files, go to your start page and click on the second link.
Next, move to the includes directory. Here you will find two new folders. The first is the data_classes. Inside this is another folder called generated. Within generated is the meat and potatoes of the ORM creation as well as some path configuration files. The files corresponding to the talbes contain all the basic CRUD (Create, Read, Update, and Delete) functionality. As we will see in a future chapter, they also contain some other interesting features. But you just have to wait. Now is not the time to going running willy-nilly into these files. We will run willy-nilly later. I promise.
Ahem. Outside the generated directory, you will find four files that correspond to the files in the generated directory. The classes in these files extend the classes in the generated folder. If you were to open one of these files in an editor, you would find that it only has one uncommented method: toString(). But why would Qcubed create files with most of it commented out? Ahh, there is a method to the madness and it is actually quite clever.
As you create your project, you may find yourself changing the structure of your database. Any change to the database requires a code regeneration so that the table changes are reflected in the ORM classes. When QCubed does this, it will ONLY replace the files in generated. The files directly under data_classes remain unaffected. This being the case, if you have any custom methods you want to create for one of the ORM classes, you would place that code into the class OUTSIDE of generated. That way, it would persist through any regenerations. And your project can still benefit from an up-to-date mapping of ORM functions to the database. Pretty nifty, huh? Well, hold on, because the ORM stuff gets even niftier later. For now though, let's move onto the last created folder, data_meta_controls.
If you take a look inside the folder, you will see a similar setup to that of the data classes folder. There are classes immediately within the folder and there is also a generated folder. Like the data classes, changes you wish to make should be done outside generated. So, what do these things do? Meta controls are something relatively new to Qcubed. In essence, they allow you to rapidly set up the controls that you will use in your forms. When making controls for database fields, you will find that many times the process is the same: create a control, give it a name, and add the corresponding data from the field. The Qcubed generation speeds this process by creating functions which will do perform these tedious actions for you. Here is an example. Don't worry about understanding WHAT all the code does for now. The more important thing to notice is typing involved. In order to create a text box for the name field of our hobby table, we would type something like
$this->txtName = new QTextBox($this); $this->txtName->Name = QApplication::Translate('Name'); $this->txtName->Text = $this->objHobby->Name; $this->txtName->Required = true; $this->txtName->MaxLength = Hobby::NameMaxLength;
With meta controls, this is placed into the meta control class as a method. So, instead of the above lines, you would type (mctHobby is the Hobby Meta control object)
$txtName = $mctHobby->txtName_Create();
And that is it. Clearly, you can see the advantage if your page contains numerous controls. The best part of these controls and QCubed itself is that you don't have to use them. You have the freedom to not use the meta controls if they do not fit your needs. Need a different label for the Name? No problem, just set up your control manually. Or maybe you could write a new method for the class in the data_meta_control folder. It is your choice what you use and what you do not. You are not tied to certain features with this code generation.
So there we have it. An initial breakdown of the code generation and what it creates. In the next chapter, we will take a close look at what exactly is created in the data classes. I will give you a hint: it has nothing to do with a delicious raspberry filling.
*If there are reasons you cannot use foreign keys in your database design, there are still ways to simulate them within QCubed. Please refer to codegen_settings.xml within the _devtools directory. Look for "Virtual Foreign Key Relationships." You can also find more explanation at http://examples.qcu.be/ under " Defining Relationships without Foreign Keys."