CakePHP’s builtin scaffolding is great but sometimes I wish it would do more or behave a little differently. Until recently, I assumed this couldn’t be accomplished with the way scaffolding was baked in. Thanks to the clever way CakePHP handles includes, we can easily use our own scaffolding implementation by adding 2 lines to AppController.

In this tutorial we will built a scaffolding plugin that is aware of the TreeBehavior. If you use scaffolding for a Tree model the parent dropdown in the add/edit view is unordered and confusing.

Non-indented Parent Association dropdown box

In our scaffolding plugin we will generate ordered/indented dropdowns for all belongsTo associations that implement the TreeBehavior. This is accomplished by calling Model->generateTreeList() instead of Model->find(‘list’). Here is an example.

Indented Parent dropdown box

To get started you want to first setup our own scaffolding implementation housed inside a plugin.

  1. Create a new CakePHP plugin

    sudo cake bake plugin TreeAwareScaffold
    

    Note: The name TreeAwareScaffold is just for illustration purposes. You can name your plugin whatever you want, but keep it descriptive. Oh, and don’t forget to share it with others via github.

  2. Create the Scaffold class

    Copy the core Scaffold class into your plugin as a starting point.

    cp lib/Cake/Controller/Scaffold.php app/Plugin/TreeAwareScaffold/Controller/ 
    

    Modify the Scaffold class to use the ScaffoldView class from your plugin (we will create it in the next step). Change line 147 to…

    $this->controller->viewClass = 'TreeAwareScaffold.Scaffold';
    
  3. Extend the Scaffold class to use generateTreeList() for Tree enabled models

    We want scaffolding to generate a nice indented dropdown list for our add and edit scaffold views but only for belongsTo associations that have the Tree behavior
    enabled.

    To accomplish this, add the following method to app/Plugin/TreeAwareScaffold/Controller/Scaffold.php

    /**
    * Detect if Tree Behavior is enabled on $Model
    *    
    * @param mixed $Model
    */
    protected function _isTree( $Model ) {
        if ( $Model->hasMethod('generateTreeList') ) { return true; }
        return false;
    }
    

    Next, Change line 274 of app/Plugin/TreeAwareScaffold/Controller/Scaffold.php from…

    $this->controller->set($varName, $this->ScaffoldModel->{$assocName}->find('list'));
    

    to the following…

    if ( $this->_isTree( $this->ScaffoldModel->{$assocName} ) ) {
        $this->controller->set($varName, $this->ScaffoldModel->{$assocName}->generateTreeList(null, null, null, '---') );
    } else {
        $this->controller->set($varName, $this->ScaffoldModel->{$assocName}->find('list'));    
    }
    
  4. Hide lft,rght fields in scaffolding

    The lft,rght columns are characteristic of Models with the Tree behavior enabled. We don’t really want to see or edit them so the following will hide them in our scaffold views.

    Note: Manually editing lft,rght field values is the primary reason for inconsistent tree tables so hiding them is a great idea!

    Replace line 137 of app/Plugin/TreeAwareScaffold/Controller/Scaffold.php

    $scaffoldFields = array_keys($this->ScaffoldModel->schema());
    

    with the following…

    /**
    * Hide the lft,rght fields for Tree Models
    * this will not work if left and right fields 
    * are named anything other than lft,left,rght,right
    */
    if ( $this->_isTree( $this->ScaffoldModel ) ) {
        $fields = $this->ScaffoldModel->schema(); 
        unset($fields['lft']); unset($fields['left']); unset($fields['rght']); unset($fields['right']); 
        $scaffoldFields = array_keys( $fields );            
    } else {
        $scaffoldFields = array_keys($this->ScaffoldModel->schema());   
    }
    
  5. Create the ScaffoldView class and scaffolding view templates

    Copy the core Scaffold View class into your plugin as a starting point.

    cp lib/Cake/View/ScaffoldView.php app/Plugin/TreeAwareScaffold/View/
    

    Copy the core scaffolding views(form.ctp, index.ctp, view.ctp) into your plugin.

    cp -r lib/Cake/View/Scaffolds app/Plugin/TreeAwareScaffold/View/
    
  6. Tell ScaffoldView to load scaffolding views from the plugin

    Edit Plugin/TreeAwareScaffold/View/ScaffoldView.php, changing line 67-68 from…

    $names[] = $this->viewPath . DS . $subDir . $scaffoldAction;
    $names[] = 'Scaffolds' . DS . $subDir . $name;
    

    to the following…

    $names[] = $this->viewPath . DS . $subDir . $scaffoldAction;
    $names[] = '..' . DS . 'Plugin' . DS . 'TreeAwareScaffold' . DS . 'View' . DS .'Scaffolds' . DS . $subDir . $name;
    $names[] = 'Scaffolds' . DS . $subDir . $name;
    

That’s it! You are ready to test drive your new scaffolding plugin.

Part 2: Using TreeAwareScaffold in your app

  1. Enable the TreeAwareScaffold plugin

    Add the following line to app/Config/bootstrap.php

    CakePlugin::load('TreeAwareScaffold');
    
  2. Configure AppController to use the new Scaffolding plugin

    App::uses('Scaffold', 'TreeAwareScaffold.Controller');
    App::uses('ScaffoldView', 'TreeAwareScaffold.View');
    
  3. Create a Category Model and enable the Tree behavior

    app/Model/Category.php

    <?php
    App::uses('AppModel', 'Model');
    class Category extends AppModel {
    
        public $displayField = 'name';
    
        public $actsAs = array('Tree');
    
        public $hasMany = array(
            'ChildCategory'=>array(
            'className'=>'Category',
            'foreignKey'=>'parent_id',
            'dependent'=>true
            )
        );
        
        public $belongsTo = array(
            'ParentCategory'=>array(
            'className'=>'Category',
            'foreignKey'=>'parent_id'
            )
        );
        
    }
    
  4. Create the associated table in MySQL

    CREATE TABLE IF NOT EXISTS `categories` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `name` varchar(128) NOT NULL,
      `parent_id` int(10) unsigned DEFAULT NULL,
      `lft` int(10) unsigned DEFAULT NULL,
      `rght` int(10) unsigned DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
    
  5. Create a CategoriesController with Scaffolding

    <?php
    App::uses('AppController', 'Controller');
    
    class CategoriesController extends AppController {
    
        public $scaffold;
    
        public $paginate = array(
            'order'=>array(
                'Category.lft'=>'asc'
            ),
            'limit'=>100   
        );
        
    }
    

More Scaffold Plugins

A list of scaffolding plugins that you can use in your CakePHP Application. If you have created a scaffolding plugin, let us hear about in the comments below and I will add it to this list.

TreeAwareScaffold – If you want to try out the plugin we created in this tutorial without following along step-by-step you can download the plugin from github!

Keywords:

  • pronique com
  • cakephp generate list scaffolding
  • cakephp 2 1 tutorial
  • what is the use of scafolding in cake php