| 1 |
Creating a simple application using the Akelos Framework |
|---|
| 2 |
========================================================= |
|---|
| 3 |
|
|---|
| 4 |
Introduction |
|---|
| 5 |
-------------------------- |
|---|
| 6 |
|
|---|
| 7 |
This tutorial teaches you how to create an application using the Akelos Framework. |
|---|
| 8 |
|
|---|
| 9 |
The application will be used for managing books and their authors and will be named **booklink** |
|---|
| 10 |
|
|---|
| 11 |
Requisites for this tutorial |
|---|
| 12 |
--------------------------- |
|---|
| 13 |
|
|---|
| 14 |
- A MySQL or SQLite Database |
|---|
| 15 |
- Apache web server |
|---|
| 16 |
- Shell access to your server |
|---|
| 17 |
- PHP4 or PHP5 |
|---|
| 18 |
|
|---|
| 19 |
This setting can be found on most Linux boxes and hosting providers. Akelos works in a myriad of settings but this tutorial focusses on this specific configuration. |
|---|
| 20 |
|
|---|
| 21 |
Download and installation |
|---|
| 22 |
--------------------------- |
|---|
| 23 |
We highly recommend you to get the trunk version of Akelos until we hit version 1.0. You need to have installed [subversion](http://subversion.tigris.org/). |
|---|
| 24 |
You can checkout a working copy of the Akelos source code with the command: |
|---|
| 25 |
|
|---|
| 26 |
svn co http://svn.akelos.org/trunk/ akelos |
|---|
| 27 |
|
|---|
| 28 |
If you can't or don't want to checkout the code from subversion, you can get the [latest stable version](http://www.akelos.org/akelos_framework-dev_preview.tar.gz) generated automatically by the Continuous Integration system, and untar it by typing: |
|---|
| 29 |
|
|---|
| 30 |
tar zxvf akelos_framework-dev_preview.tar.gz;mv akelos_framework-dev_preview akelos |
|---|
| 31 |
|
|---|
| 32 |
Now we need to be sure that akelos can find your PHP version by running |
|---|
| 33 |
|
|---|
| 34 |
/usr/bin/env php -v |
|---|
| 35 |
|
|---|
| 36 |
If you see something like |
|---|
| 37 |
|
|---|
| 38 |
PHP 5.1.2 (cli) (built: Jan 17 2006 15:00:28) |
|---|
| 39 |
Copyright (c) 1997-2006 The PHP Group |
|---|
| 40 |
Zend Engine v2.1.0, Copyright (c) 1998-2006 Zend Technologies |
|---|
| 41 |
|
|---|
| 42 |
you're on the right track and can continue creating an Akelos application; otherwise you'll need to find out the path to your PHP binary, usually with |
|---|
| 43 |
|
|---|
| 44 |
which php |
|---|
| 45 |
|
|---|
| 46 |
And change the `#!/usr/bin/env php` at the beginning of these files `script/console`, `script/generate`, `script/migrate`, `script/setup` and `script/test` to your php binary path. |
|---|
| 47 |
|
|---|
| 48 |
**Note for Windows users:** You will need to call the scripts from your application directory using the full path to your php.exe file like: |
|---|
| 49 |
|
|---|
| 50 |
C:\Program Files\xampp\php\php.exe ./script/generate scaffold |
|---|
| 51 |
|
|---|
| 52 |
Setting up a new Akelos application |
|---|
| 53 |
--------------------------------------------- |
|---|
| 54 |
|
|---|
| 55 |
You have downloaded Akelos and made sure you'll be able to run PHP scripts from your console (not necessary to run Akelos, but it's required for this tutorial) |
|---|
| 56 |
|
|---|
| 57 |
Now you can follow two paths: |
|---|
| 58 |
|
|---|
| 59 |
1. Create an Akelos application in a different folder and link it to the Framework libraries. |
|---|
| 60 |
2. Start coding your application from this folder with the security implications that has making available to the visitors of your site all your Application models, views, 3rd party libraries and so on. |
|---|
| 61 |
|
|---|
| 62 |
As you might have guessed you should go with the first option and create a linked Akelos application which will only expose the public folder to the world. Changing the Framework paths is really simple in Akelos, all you have to do is define in your configuration file where each component is located, but we will leave this for a future tutorial about designing an application for distributing it. |
|---|
| 63 |
|
|---|
| 64 |
Assuming you've downloaded the framework to `HOME_DIR/akelos` and that you are inside the `akelos` directory you will check available options for setting up your new application by running |
|---|
| 65 |
|
|---|
| 66 |
./script/setup -h |
|---|
| 67 |
|
|---|
| 68 |
which will show us available options for the installer |
|---|
| 69 |
|
|---|
| 70 |
Usage: setup [-sqphf --dependencies] <-d> |
|---|
| 71 |
|
|---|
| 72 |
-deps --dependencies Includes a copy of the framework into the application |
|---|
| 73 |
directory. (true) |
|---|
| 74 |
-d --directory=<value> Destination directory for installing the application. |
|---|
| 75 |
-f --force Overwrite files that already exist. (false) |
|---|
| 76 |
-h --help Show this help message. |
|---|
| 77 |
-p --public_html=<value> Location where the application will be accesed by the |
|---|
| 78 |
webserver. () |
|---|
| 79 |
-q --quiet Suppress normal output. (false) |
|---|
| 80 |
-s --skip Skip files that already exist. (false) |
|---|
| 81 |
|
|---|
| 82 |
So running this command: (replace `/www/htdocs` with your web server public path. On some shared server it's `/home/USERNAME/public_html`) |
|---|
| 83 |
|
|---|
| 84 |
./script/setup -d HOMEDIR/booklink -p /www/htdocs/booklink |
|---|
| 85 |
|
|---|
| 86 |
This will create the following structure for the **booklink** application: |
|---|
| 87 |
|
|---|
| 88 |
booklink/ |
|---|
| 89 |
app/ << The application including controllers, views, models and installers |
|---|
| 90 |
config/ << Boring configuration files (will do the config via web) |
|---|
| 91 |
public/ << This is the only folder made public under /www/htdocs/booklink softlink |
|---|
| 92 |
script/ << Utils for code generation and running tests |
|---|
| 93 |
|
|---|
| 94 |
**Note for Windows users:** A soft link to booklink/public is created only on *NIX systems, so you'll need to tell your web server where to find the public path for the **booklink** application on your `httpd.conf` file by adding something like this: |
|---|
| 95 |
|
|---|
| 96 |
Alias /booklink "/path/to_your/booklink/public" |
|---|
| 97 |
|
|---|
| 98 |
<Directory "/path/to_your/booklink/public"> |
|---|
| 99 |
Options Indexes FollowSymLinks |
|---|
| 100 |
AllowOverride All |
|---|
| 101 |
Order allow,deny |
|---|
| 102 |
Allow from all |
|---|
| 103 |
</Directory> |
|---|
| 104 |
|
|---|
| 105 |
and then restart your web server. |
|---|
| 106 |
|
|---|
| 107 |
### Creating a database for your application ### |
|---|
| 108 |
|
|---|
| 109 |
Next thing you'll need is to create a database for your application. If you intend to use SQLite on PHP5 skip this step. |
|---|
| 110 |
|
|---|
| 111 |
Creating a MySQL database is out of the scope of this tutorial so you might need to google how to do this on your system or just try this common scenario where you can create 3 different databases one for each different environment (production, development and testing). |
|---|
| 112 |
|
|---|
| 113 |
mysql -u root -p |
|---|
| 114 |
|
|---|
| 115 |
mysql> CREATE DATABASE booklink; |
|---|
| 116 |
mysql> CREATE DATABASE booklink_dev; |
|---|
| 117 |
mysql> CREATE DATABASE booklink_tests; |
|---|
| 118 |
|
|---|
| 119 |
mysql> GRANT ALL ON booklink.* TO bermi@localhost IDENTIFIED BY "pass"; |
|---|
| 120 |
mysql> GRANT ALL ON booklink_dev.* TO bermi@localhost IDENTIFIED BY "pass"; |
|---|
| 121 |
mysql> GRANT ALL ON booklink_tests.* TO bermi@localhost IDENTIFIED BY "pass"; |
|---|
| 122 |
|
|---|
| 123 |
mysql> FLUSH PRIVILEGES; |
|---|
| 124 |
mysql> exit |
|---|
| 125 |
|
|---|
| 126 |
If you are on a shared hosted server you might need to create it from your hosting provider control panel. |
|---|
| 127 |
|
|---|
| 128 |
### Generating the configuration file ### |
|---|
| 129 |
|
|---|
| 130 |
#### Using the web installer #### |
|---|
| 131 |
|
|---|
| 132 |
Now you can visit your application configuration wizard at http://localhost/booklink |
|---|
| 133 |
|
|---|
| 134 |
Follow the steps in the wizard to set up your database, locales and file permissions and generate a configuration file. I'll go for a coffee while you do that so you can continue creating the **booklink** app. |
|---|
| 135 |
|
|---|
| 136 |
#### Manual configuration editing #### |
|---|
| 137 |
|
|---|
| 138 |
Save the files `config/DEFAULT-config.php` and `config/DEFAULT-routes.php` as `config/config.php` and `config/routes.php` and edit them following them as needed. |
|---|
| 139 |
|
|---|
| 140 |
You might also need to set the base rewrite path manually if you want to be able to use nice URLs by editing the file `public/.htaccess` and setting RewriteBase like: |
|---|
| 141 |
|
|---|
| 142 |
RewriteBase /booklink |
|---|
| 143 |
|
|---|
| 144 |
After your application has been installed correctly you'll see a welcome message at http://localhost/booklink. Now you can safely remove the framework setup files (they won't be accessible if a `/config/config.php` file exists) |
|---|
| 145 |
|
|---|
| 146 |
The booklink database structure |
|---|
| 147 |
--------------------------------- |
|---|
| 148 |
|
|---|
| 149 |
Now you need to define the tables and columns where your application will hold the information about books and authors. |
|---|
| 150 |
|
|---|
| 151 |
When working with other developers database changes can be difficult to distribute among them. Akelos has a solution for this problem named *installer* or *migration*. |
|---|
| 152 |
|
|---|
| 153 |
So you will create the database using an installer in order to distribute the changes you make to the booklink database scheme from time to time. |
|---|
| 154 |
Using *installers* will also allow you to define your database tables and columns independently from the database vendor. |
|---|
| 155 |
|
|---|
| 156 |
Now you will create a file named `app/installers/booklink_installer.php` with the following Installer code |
|---|
| 157 |
|
|---|
| 158 |
<?php |
|---|
| 159 |
|
|---|
| 160 |
class BooklinkInstaller extends AkInstaller |
|---|
| 161 |
{ |
|---|
| 162 |
function up_1(){ |
|---|
| 163 |
|
|---|
| 164 |
$this->createTable('books', |
|---|
| 165 |
'id,'. // the key |
|---|
| 166 |
'title,'. // the title of the book |
|---|
| 167 |
'description,'. // a description of the book |
|---|
| 168 |
'author_id,'. // the author id. This is how Akelos will know how to link |
|---|
| 169 |
'published_on' // the publication date |
|---|
| 170 |
); |
|---|
| 171 |
|
|---|
| 172 |
$this->createTable('authors', |
|---|
| 173 |
'id,'. // the key |
|---|
| 174 |
'name' // the name of the author |
|---|
| 175 |
); |
|---|
| 176 |
} |
|---|
| 177 |
|
|---|
| 178 |
function down_1(){ |
|---|
| 179 |
$this->dropTables('books','authors'); |
|---|
| 180 |
} |
|---|
| 181 |
} |
|---|
| 182 |
|
|---|
| 183 |
?> |
|---|
| 184 |
|
|---|
| 185 |
That's enough for Akelos to create your database schema. If you just specify the column name, Akelos will default to the best data type based on database normalization conventions. If you want to have full control over your table settings, you can use [php Adodb Datadict syntax](http://phplens.com/lens/adodb/docs-datadict.htm) |
|---|
| 186 |
|
|---|
| 187 |
Now we need to execute the installer with the command |
|---|
| 188 |
|
|---|
| 189 |
./script/migrate Booklink install |
|---|
| 190 |
|
|---|
| 191 |
and that will do the trick. If we are using MySQL the database will look something like this: |
|---|
| 192 |
|
|---|
| 193 |
**BOOKS TABLE** |
|---|
| 194 |
|
|---|
| 195 |
+--------------+--------------+------+-----+----------------+ |
|---|
| 196 |
| Field | Type | Null | Key | Extra | |
|---|
| 197 |
+--------------+--------------+------+-----+----------------+ |
|---|
| 198 |
| id | int(11) | NO | PRI | auto_increment | |
|---|
| 199 |
| title | varchar(255) | YES | | | |
|---|
| 200 |
| description | longtext | YES | | | |
|---|
| 201 |
| author_id | int(11) | YES | MUL | | |
|---|
| 202 |
| published_on | date | YES | | | |
|---|
| 203 |
| updated_at | datetime | YES | | | |
|---|
| 204 |
| created_at | datetime | YES | | | |
|---|
| 205 |
+--------------+--------------+------+-----+----------------+ |
|---|
| 206 |
|
|---|
| 207 |
**AUTHORS TABLE** |
|---|
| 208 |
|
|---|
| 209 |
+--------------+--------------+------+-----+----------------+ |
|---|
| 210 |
| Field | Type | Null | Key | Extra | |
|---|
| 211 |
+--------------+--------------+------+-----+----------------+ |
|---|
| 212 |
| id | int(11) | NO | PRI | auto_increment | |
|---|
| 213 |
| name | varchar(255) | YES | | | |
|---|
| 214 |
| updated_at | datetime | YES | | | |
|---|
| 215 |
| created_at | datetime | YES | | | |
|---|
| 216 |
+--------------+--------------+------+-----+----------------+ |
|---|
| 217 |
|
|---|
| 218 |
|
|---|
| 219 |
Models, Views and Controllers |
|---|
| 220 |
------------------------------------------------------ |
|---|
| 221 |
|
|---|
| 222 |
Akelos follows the [MVC design pattern](http://en.wikipedia.org/wiki/Model-view-controller) for organizing your application. |
|---|
| 223 |
|
|---|
| 224 |
 |
|---|
| 225 |
|
|---|
| 226 |
### Your application files and the Akelos Naming conventions ### |
|---|
| 227 |
|
|---|
| 228 |
These are the conventions that empower the Akelos [convention over configuration](http://en.wikipedia.org/wiki/Convention_over_Configuration) philosophy. |
|---|
| 229 |
|
|---|
| 230 |
#### Models #### |
|---|
| 231 |
|
|---|
| 232 |
* **Path:** /app/models/ |
|---|
| 233 |
* **Class Name:** singular, camel cased *(BankAccount, Person, Book)* |
|---|
| 234 |
* **File Name:** singular, underscored *(bank_account.php, person.php, book.php)* |
|---|
| 235 |
* **Table Name:** plural, underscored *(bank_accounts, people, books)* |
|---|
| 236 |
|
|---|
| 237 |
#### Controllers #### |
|---|
| 238 |
|
|---|
| 239 |
* **Path:** */app/controllers/* |
|---|
| 240 |
* **Class Name:** singular or pural, camel cased, ends in `Controller` *(AccountController, PersonController)* |
|---|
| 241 |
* **File Name:** singular or pural, underscored, ends in `_controller` *(`account_controller.php`, `person_controller.php`)* |
|---|
| 242 |
|
|---|
| 243 |
#### Views #### |
|---|
| 244 |
|
|---|
| 245 |
* **Path:** /app/views/ + *underscored_controller_name/* *(app/views/person/)* |
|---|
| 246 |
* **File Name:** action name, lowercase *(app/views/person/show.tpl)* |
|---|
| 247 |
|
|---|
| 248 |
|
|---|
| 249 |
Akelos scaffolding |
|---|
| 250 |
------------------------------------------ |
|---|
| 251 |
|
|---|
| 252 |
Akelos comes with code generators that can cut your development time by creating fully functional [scaffold code](http://en.wikipedia.org/wiki/Scaffold_(programming)) that you can use as a departure/learning point. |
|---|
| 253 |
|
|---|
| 254 |
### Meet the Scaffold generator ### |
|---|
| 255 |
|
|---|
| 256 |
You will generate a base skeleton for interacting with the **booklink** database created before. In order to get this skeleton quickly you can use the *scaffold generator* like this |
|---|
| 257 |
|
|---|
| 258 |
./script/generate scaffold Book |
|---|
| 259 |
|
|---|
| 260 |
and |
|---|
| 261 |
|
|---|
| 262 |
./script/generate scaffold Author |
|---|
| 263 |
|
|---|
| 264 |
This will generate a bunch of files and folders with code that really works!. Don't trust me? Try it yourself. Point your browser to [http://localhost/booklink/author](http://localhost/booklink/author) and [http://localhost/booklink/book](http://localhost/booklink/book) or to [http://localhost/booklink/?ak=author](http://localhost/booklink/?ak=author) and [http://localhost/booklink/?ak=book](http://localhost/booklink/?ak=book) in case mod_rewrite is disabled to start adding authors and books. Create some records and come back for an explanation of what is going under the hood. |
|---|
| 265 |
|
|---|
| 266 |
|
|---|
| 267 |
The Akelos Workflow |
|---|
| 268 |
------------------------------------------ |
|---|
| 269 |
|
|---|
| 270 |
This is a small description of the workflow for a call to the following URL `http://localhost/booklink/book/show/2` |
|---|
| 271 |
|
|---|
| 272 |
1. Akelos will break up your request into three parameters according to your `/config/routes.php` file (more on this later) |
|---|
| 273 |
* controller: book |
|---|
| 274 |
* action: show |
|---|
| 275 |
* id: 2 |
|---|
| 276 |
|
|---|
| 277 |
2. Once Akelos knows about this request it will look for the file `/app/controllers/book_controller.php` and if found it will instantiate the class `BookController` |
|---|
| 278 |
|
|---|
| 279 |
3. The controller will look for a model that matches the parameter `controller` from the request. In this case it will look for `/app/models/book.php`. If found, it will create an instance of the model on the controller `$this->Book` attribute. If an `id` is on the request, it will search into the database for the Book with the id 2 and that will remain on `$this->Book` |
|---|
| 280 |
|
|---|
| 281 |
4. Now it will call the action `show` from the `BookController` class if it's available. |
|---|
| 282 |
|
|---|
| 283 |
5. Once the show action has been executed, the controller will look for the view file at `/app/views/book/show.tpl` and will render the results into the `$content_for_layout` variable. |
|---|
| 284 |
|
|---|
| 285 |
6. Now Akelos will look for a layout named like the controller at `/app/views/layouts/book.tpl`. If found it will render the layout inserting `$content_for_layout` content and sending the output to the browser. |
|---|
| 286 |
|
|---|
| 287 |
This might help you understanding the way Akelos handles your requests, so we are ready to modify the base application. |
|---|
| 288 |
|
|---|
| 289 |
|
|---|
| 290 |
Relating Books and Authors |
|---|
| 291 |
---------------------------- |
|---|
| 292 |
|
|---|
| 293 |
Now you are going to link authors and books (complex associations in upcoming tutorials). In order to achieve this you will use the `author_id` column you added to your database. |
|---|
| 294 |
|
|---|
| 295 |
So you will need to tell your models how they relate to each other like |
|---|
| 296 |
|
|---|
| 297 |
*/app/models/book.php* |
|---|
| 298 |
|
|---|
| 299 |
<?php |
|---|
| 300 |
|
|---|
| 301 |
class Book extends ActiveRecord |
|---|
| 302 |
{ |
|---|
| 303 |
var $belongs_to = 'author'; // <- declaring the association |
|---|
| 304 |
} |
|---|
| 305 |
|
|---|
| 306 |
?> |
|---|
| 307 |
|
|---|
| 308 |
*/app/models/author.php* |
|---|
| 309 |
|
|---|
| 310 |
<?php |
|---|
| 311 |
|
|---|
| 312 |
class Author extends ActiveRecord |
|---|
| 313 |
{ |
|---|
| 314 |
var $has_many = 'books'; // <- declaring the association |
|---|
| 315 |
} |
|---|
| 316 |
|
|---|
| 317 |
?> |
|---|
| 318 |
|
|---|
| 319 |
Now that you made the models aware of each other you will need to modify the book controller so it loads the `author` and the `book` model instances |
|---|
| 320 |
|
|---|
| 321 |
*/app/controllers/book_controller.php* |
|---|
| 322 |
|
|---|
| 323 |
<?php |
|---|
| 324 |
|
|---|
| 325 |
class BookController extends ApplicationController |
|---|
| 326 |
{ |
|---|
| 327 |
var $models = 'book, author'; // <- make these models available |
|---|
| 328 |
|
|---|
| 329 |
// ... more BookController code |
|---|
| 330 |
|
|---|
| 331 |
function show() |
|---|
| 332 |
{ |
|---|
| 333 |
// Replace "$this->book = $this->Book->find(@$this->params['id']);" |
|---|
| 334 |
// with this in order to find related authors. |
|---|
| 335 |
$this->book = $this->Book->find(@$this->params['id'], array('include' => 'author')); |
|---|
| 336 |
} |
|---|
| 337 |
|
|---|
| 338 |
// ... more BookController code |
|---|
| 339 |
} |
|---|
| 340 |
|
|---|
| 341 |
Next step is to show available authors when creating or editing a book. This can be achieved using the `$form_options_helper` by inserting the following code |
|---|
| 342 |
right after `<?=$active_record_helper->error_messages_for('book');?>` on the */app/views/book/_form.tpl* file |
|---|
| 343 |
|
|---|
| 344 |
<p> |
|---|
| 345 |
<label for="author">_{Author}</label><br /> |
|---|
| 346 |
<?=$form_options_helper->select('book', 'author_id', $Author->collect($Author->find(), 'name', 'id'));?> |
|---|
| 347 |
</p> |
|---|
| 348 |
|
|---|
| 349 |
If you have not added authors yet, go and create some right now and then visit http://locahost/booklink/book/add to check out the brand new authors select list. Go ahead and create a new book selecting an author from the list. |
|---|
| 350 |
|
|---|
| 351 |
Seems like the author has been saved but it its not included on the `app/views/book/show.tpl` view. You'll add it this code right after `<? $content_columns = array_keys($Book->getContentColumns()); ?>` |
|---|
| 352 |
|
|---|
| 353 |
<label>_{Author}:</label> <span class="static">{book.author.name?}</span><br /> |
|---|
| 354 |
|
|---|
| 355 |
The final step - show the author in the listing. In order to do it replace the last string of the listing method in book_controller.php with the following text: |
|---|
| 356 |
|
|---|
| 357 |
$find_options = $this->pagination_helper->getFindOptions($this->Book); |
|---|
| 358 |
$find_options['include'] = 'author'; |
|---|
| 359 |
$this->books =& $this->Book->find('all', $find_options); |
|---|
| 360 |
|
|---|
| 361 |
Now we can edit `app/views/book/listing.tpl`: |
|---|
| 362 |
* insert new string `<th>_{Author}</th>` right before `<?php $content_columns = array_keys($Book->getContentColumns()); ?>` |
|---|
| 363 |
* Make the template to output author'a name by adding `<td>{post.user.login?}</td>` after `<tr {?post_odd_position}class="odd"{end}>` |
|---|
| 364 |
|
|---|
| 365 |
You must be screaming now about the rare `_{Author}` and `{book.author.name?}` syntax. Thats actually [Sintags](http://www.bermi.org/projects/sintags) a small set of rules that helps on writing cleaner views and that will be compiled to standard PHP. |
|---|
| 366 |
|
|---|
| 367 |
|
|---|
| 368 |
Colophon |
|---|
| 369 |
-------------------- |
|---|
| 370 |
|
|---|
| 371 |
This is all for now, I'll be improving this tutorial from time to time to add some missing features to this and other documents like: |
|---|
| 372 |
|
|---|
| 373 |
* validations |
|---|
| 374 |
* routes |
|---|
| 375 |
* filters |
|---|
| 376 |
* callbacks |
|---|
| 377 |
* transactions |
|---|
| 378 |
* console |
|---|
| 379 |
* AJAX |
|---|
| 380 |
* helpers |
|---|
| 381 |
* web services |
|---|
| 382 |
* testing |
|---|
| 383 |
* distributing |
|---|
| 384 |
* and many more... |
|---|
| 385 |
|
|---|
| 386 |
My apologies for any typo or grammatical error you might find. English is not my mother tongue and I would really like you to help me [improving and fixing errors in this document](http://trac.akelos.org/newticket?keywords=booklink%20english&component=Documentation&priority=minor&type=documentation&summary=Booklin%20Tutorial%20improvements). |
|---|