BookDB – Step 0: Glueing stuff together

A

I have an idea involving a site about books. So I thought I’ll build it in small increments adding in all sorts of stuff I’ve been wanting to incorporate into the design flow: unit testing, ORM, automated deployment, getting rich etc.

As I’ve said before, I tend to waste my time from time to time and experiment with other languages/frameworks/technologies. I like to fool myself  I’m acquiring  skills, which will eventually end up in my CV, when I’m actually just de-stressing. Some people do yoga, I download and install django.

Django seemed nice, had nice automation tools to start your project, schema files, generates a basic admin that you can easily extend, has a large ecosistem of modules and applications. But then I realised the very same ecosistem is too new for me and getting this rather large project off the ground would take too long and I tend to give up if there is no quick reward, no satisfaction. I like to see stuff in the browser right away, I’ll reasd the docs after that. But I like the idea of having an ORM and schema files you can version, plus a tool to generate applications, models, tables etc.

I knew about the two big players in the php ORM world, Doctrine, used by the Symfony Project and Propel. I had used Doctrine and spent a week-end reading their docs and looking at examples before, on a small community site I had build using Adi’s framework (which will be the greatest php framework, but only after it reaches a number of 1000 complete re-writes so that it can incorporate perfection). So I chose Doctrine and Zend Framework. Zend also comes with PHPUnit. I’ll worry about Phing later, when everything works and there is something to move around in svn.

First issue was bootstrapping ZF. Which took a while, but I wrote about that in another post.

I installed ZF from the Ubuntu repository. That was simple. I then ran zf.sh create project bookdb (after symlinking it from where it was installed in ubuntu) in my webserver docroot (I’ll worry about creating a vhost later, i just want to get it working).

I had this in the index.php it generated in the public folder:


<?php

// Define path to application directory
defined('APPLICATION_PATH')
 || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
 || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
 realpath(APPLICATION_PATH . '/../library'),
 realpath(APPLICATION_PATH . '/models'),
 realpath(APPLICATION_PATH . '/models/generated'),
 get_include_path(),
)));

/** Zend_Application */
require_once 'Zend/Application.php';

// Create application, bootstrap, and run
$application = new Zend_Application(
 APPLICATION_ENV,
 APPLICATION_PATH . '/configs/application.ini'
);
$application->bootstrap()
 ->run();

And this in the Bootstrap.php file from the application folder:


<?php

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{

}

Then came the fun part of figuring out what and HOW to do with this Bootstrap class/file. And if you think you know what fun is, read the previous post.

Then I started to understand a bit. You can add methods in this class and if you prefix their name with _init then you should be able to do stuff like $application->bootstrap(‘db’) considering you defined a method called  _initDb in your bootstrap class. If you don’t pass it any arguments it just calls all the functions defined.

So the simplest idea I could think of, after twisting my brain to understand these pages from the ZF documentation, was to add the usual stuff I needed in my old-style boostrap file I used for previous (pre ZF 1.8) projects in a method called _initDb.

Then, cos I needed Doctrine, i switched it to this (after previously checking out Doctrine from their svn in my library folder):


protected function _initDoctrine(){
 require_once 'Doctrine.php';
 spl_autoload_register(array('Doctrine', 'autoload'));
 spl_autoload_register(array('Doctrine', 'modelsAutoload'));

 $dsn = 'mysql:dbname=bookdb_php;host=localhost';
 $user = 'user';
 $password = 'password';

 $dbh = new PDO($dsn, $user, $password);
 $conn = Doctrine_Manager::connection($dbh);

 $doctrine_config = array(
 'data_fixtures_path'  =>  dirname(__FILE__).'/doctrine/data/fixtures',
 'models_path'         =>  dirname(__FILE__).'/models',
 'migrations_path'     =>  dirname(__FILE__).'/doctrine/migrations',
 'sql_path'            =>  dirname(__FILE__).'/doctrine/data/sql',
 'yaml_schema_path'    =>  dirname(__FILE__).'/doctrine/schema'
 );

 Zend_Registry::set('doctrine_config', $doctrine_config);
 }

Of course, you need to create the doctrine folder in your application area.

Ok, since I liked django’s tools I also wanted to use Doctrine’s generation tool and for that I needed a php script that I could call from the shell.

I basically replicated the index.php from above and only changed the last line (cos you don’t actually need to run the mvc part for this) and added two new lines.

$application->bootstrap();

$cli = new Doctrine_Cli(Zend_Registry::get('doctrine_config'));
$cli->run($_SERVER['argv']);

Saved this as doctrine-cli in the scripts folder, ran chmod +x on it and that was it.

All I needed now was a schema.yml file in my doctrine/schema folder.


Book:
 columns:
  id:
   primary: true
   autoincrement: true
   type: integer(4)
  name:
   type: string(100)
  added:
   type: timestamp

Then I hoped all that had remained to do was to run this in shell:

./doctrine-cli generate-models-yaml
./doctrine-cli generate-sql
./doctrine-cli create-tables

All went through without problem, so I thought. Checked the tables in the database. No book table there.

The index file above instructs the framework not to spit out any errors, so I changed that and ran the last shell command again.


Fatal error: Class 'BaseBook' not found in /var/www/bookdb/application/models/Book.php on line 13

Aha. So someone is not finding the model classes, even though they were there by now.

The Book model Doctrine created in Book.php in my model folder extended BaseBook, from models/generated/BaseBook.php.

Ok, lets see if Book works. I added $b = new Book() to the empty IndexController and checked the site again: Fatal error: Class ‘Book’ not found in /var/www/bookdb/application/controllers/IndexController.php on line 14.

Nice, I forgot about the autoloader. I added another method to the bootstrap class. To see why you need to add a fallback namespace loader now, read this. Using the old style auloader will throw a warning that your old ways are old and you will be obsoleted in the next version. Cos autoloaders need to be comprehensive now, they just can’t be simple. Again, read the link above.


protected function _initAutoload()
 {
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->setFallbackAutoloader(true);

 }

Repeated the doctrine-cli commands from shell and refreshed the browser. Lo and behold, no errors!

I quickly added two more lines in the index action of the Index controller and refreshed.


$b->name = 'Zend Framework for Dummies';
 $b->save();

No errors and more than that I had a new line in my newly created Book table.

I felt powerful, I felt smart. I had cracked the secret code, I had joined the masters. Next step, refactoring. I’m pretty sure a large part of the above is stupid, but it works.

Stay tuned, more to come.

  1. olgaevkud says:

    Рад встрече большая часть пользователей интернета рано или поздно знакомится в сети , конечно пользователи разные и каждый ищет что то для себя кто ищет знакомства для брака.Но бывают и неоднозначные странные запросы.
    знакомства без обязательств интим знакомства онлайн знакомства елань волгоградская обл

  1. [...] main issue was that I also wanted modules with my fries. So whatever I wrote in Step 0 is either incomplete or [...]

Leave a Reply