Day2 - Adding Models and few CRUDs

Summary: Today I plan to add model classes, create database and vizualize my data. Vizualization is the most important as it will help me to confirm that my model structure works, will allow me to enter some data in and test dependencies between models.

Browse PHP source from this day

Creating Models Classes

Agile Toolkit does not offer a generator for models. You can make a short snippet in your favourite text editor, which will in fact work for ANY class.

class Model_Customer extends Model_Table {
    function 
init(){
        
parent::init();


    }
}

There is only one property you should re-define in your model, called $entity_code and containing name of your SQL table. (Use with no-SQL is planned in 4.2 release of Agile Toolkit). Majority of the properties and methods in Agile Toolkit are public, so that they can be accessed by controllers.

Second thing we are going to define are the fields. With very little information about our requirements we will try to keep our model definition very brief. By default Model also defines a system field "id" which is used as a primary index.

Add the below code into files lib/Model/Customer.php, lib/Model/Movie.php, lib/Model/DVD.php and lib/Model/Rental.php.

class Model_Customer extends Model_Table {
    public 
$entity_code='customer';
    function 
init(){
        
parent::init();

        
$this->addField('name');
    }
}
class 
Model_Movie extends Model_Table {
    public 
$entity_code='movie';
    function 
init(){
        
parent::init();

        
$this->addField('name');
        
$this->addField('year')->type('int');
        
$this->addField('imdb')->caption('IMDB Link');
    }
}
class 
Model_DVD extends Model_Table {
    public 
$entity_code='dvd';
    function 
init(){
        
parent::init();

        
$this->addField('movie_id')->refModel('Model_Movie');
        
$this->addField('code');
    }
    function 
toStringSQL($source_field$dest_fieldname){
        return 
'concat("DVD#",id,": ",(select name 
                    from movie m,dvd d where m.id=d.movie_id and d.id='
.$source_field.')) as '.$dest_fieldname;
    }
}
class 
Model_Rental extends Model_Table {
    public 
$entity_code='rental';
    function 
init(){
        
parent::init();

        
$this->addField('customer_id')->refModel('Model_Customer');
        
$this->addField('dvd_id')->refModel('Model_DVD');
        
$this->addField('date_rented')->defaultValue(date('Y-m-d'))->type('date');
        
$this->addField('date_returned')->type('date');
        
        
$this->addField('is_returned')->type('boolean')->defaultValue(false);
    }
    function 
returnMovie(){
        
$this
            
->set('date_returned',date('Y-m-d'))
            ->
set('is_returned',true)
            ->
update();
    }
}

In Agile Toolkit inheritance of Models is a major tool which should be used. Further on we will define some additional models such as "RentedDVD" etc as well as introduce relation into Model_DVD. For now let's focus on simplicity and getting some initial data into the database.

Building administrative CRUDs

It's suggested that as soon as you create models, you also visualise them in the backend. It requires virtually no effort at all.

Let's create a new page "mgr" through the file page/mgr.php. Remember that file and class case must always carefully match.

class page_mgr extends Page {
    function 
init(){
        
parent::init();

        
$tabs=$this->add('Tabs');
        
$tabs->addTab('Customers')->add('CRUD')->setModel('Customer');
        
$tabs->addTab('Movies')->add('CRUD')->setModel('Movie');
        
$tabs->addTab('DVDs')->add('CRUD')->setModel('DVD');
        
$tabs->addTab('Rentals')->add('CRUD')->setModel('Rental');
    }
}

You will also need to open your Application class (lib/Frontend.php) and add (or un-comment) call to dbConnect() as we will need to access database. Copy your config-distrib.php into config.php and edit it to make sure your database settings are set properly. More info on configuration

Finally let's add the page to the menu of our application, by locating 'Menu' object in lib/Frotend.php and adding new addMenuItem calls.

        $menu->addMenuItem('mgr','Manager');

Also make sure that atk4-addons directory is properly included into resource paths. The followind should already be inside init() method:

        $this->addLocation('atk4-addons',array(
                    
'php'=>array(
                        
'mvc',
                        
'misc/lib',
                        )
                    ))
            ->
setParent($this->pathfinder->base_location);

Create folder "doc" in your application root. Create a doc/.htaccess file with "deny from all" inside it to restrict direct access (you can also keep the folder outside of your web root). Database migration requires you to have "bash" which comes with any unix or linux. If you are on windows, you can install cygwin, bash port, or execute upgrade files manually. The reason why upgardes are done through the command-line is because in secure environment you would have a separate username with create/alter priviledges and database user from config.php wouldn't be able to perform those operations.

Below is the "base" schema. Save it in doc/dvdrental-001.sql.

CREATE TABLE `movie` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `year` int(11) DEFAULT NULL,
  `imdb` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);
INSERT INTO `movie` VALUES 
    (1,'V for Vendetta',2006,'http://www.imdb.com/title/tt0434409/'),
    (2,'The Matrix',1999,'http://www.imdb.com/title/tt0133093/'),
    (3,'WALL-E',2008,'http://www.imdb.com/title/tt0910970/');

CREATE TABLE `dvd` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `movie_id` int(11) DEFAULT NULL,
  `code` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO `dvd` VALUES
    (1,2,'20397728'),
    (2,1,'20397729'),
    (3,1,'20397730');

CREATE TABLE `customer` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO `customer` VALUES 
    (1,'John Smith'),
    (2,'Peter Taylor');

CREATE TABLE `rental` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `customer_id` int(11) DEFAULT NULL,
  `dvd_id` int(11) DEFAULT NULL,
  `date_rented` varchar(255) DEFAULT NULL,
  `date_returned` varchar(255) DEFAULT NULL,
  `is_returned` enum('Y','N') DEFAULT NULL,
  PRIMARY KEY (`id`)
);

INSERT INTO `rental` VALUES 
    (1,1,1,'2011-08-21','','N'),
    (2,1,2,'2011-08-18','2011-08-21','Y');

Once your data structure is ready, go straight into the Management page and you will be able to have full control over created data.

---------- movie ----------
Where is Testing??

You have just created the simplest and most flexible administration interface. Believe me, we still have only touched the surface of our application. It might have taken you 15 minutes to create this yet if you show this to your client, he would be highly impressed and ready to come up with the next set of tasks.