View Source

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[{zone-template-instance:ZFPROP:Proposal Zone Template}

{zone-data:component-name}
Zend_Controller_Scaffolding
{zone-data}

{zone-data:proposer-list}
[Alex Oroshchuk|mailto:oroshchuk@gmail.com]
{zone-data}

{zone-data:liaison}
TBD
{zone-data}

{zone-data:revision}
1.0 - Aug 2010: Initial Draft.
{zone-data}

{zone-data:overview}
{{Zend_Controller_Scaffolding}} will provide quick scaffolding features (that every mature framework has) by extending Zend_Controller_Action class. *The component has a real code base ([https://github.com/lex0r/zendscaffolding]) and is used in several projects*.
{zone-data}

{zone-data:references}
Guthub Project: [https://github.com/lex0r/zendscaffolding]
{zone-data}

{zone-data:requirements}
* This component provides typical scaffolding actions like CReate, Update and Delete, as well as data lists.
* This component allows to easily mix scaffolding and custom actions.
* This component allows to use custom views for scaffolding actions by setting a view path.
* This component supports sorting of data lists.
* This component supports partially (and *will* provide a larger support) data list filtering by one or more data fields.
* This component supports pagination of data lists.
* This component supports custom select statements (Zend_Db_Select or Zend_Db_Table_Select) for specific data lists.
* This component provides several callbacks (through overriding of protected methods) to customize edit and search forms and enhance user experience.
* This component supports data relationships (and *will* provide a larger support) when editing related entities (like one-to-many and many-to-many).
* This component allows to restrict certain scaffolding actions and/or provide data listing only.
* This component *will* support scaffolding configuration through Zend_Config.
{zone-data}

{zone-data:dependencies}
* {{Zend_Controller}}
* {{Zend_Db}}
* {{Zend_View}}
* {{Zend_Form}}
* {{Zend_Pagination}}
* {{Zend_Validate}}
* {{Zend_Filter}}
{zone-data}

{zone-data:operation}
There are several steps:
* Decide on data fields available for edition/listing/sorting/search and prepare two configuration structures: list of data (or synthetic) fields and general scaffolding options (like custom view folder, pagination etc.)
* Initialize scaffolding by passing 3 parameters: data providing class instance and the two configuration structures.
{zone-data}

{zone-data:milestones}
Component has a stable release on Github.
{zone-data}

{zone-data:class-list}
* {{Zend_Controller_Scaffolding}}
{zone-data}

{zone-data:use-cases}
{composition-setup}
{deck:id=use-cases}
{card:label=UC-1: typical usage}
+Using scaffolding in a typical situation - back-end user management interface.+
Suppose we have a (MySQL) table *users* with the following structure:
{code}
CREATE TABLE `users` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`username` VARCHAR(32) NOT NULL,
`password` CHAR(32) NOT NULL,
`created_at` DATETIME NOT NULL
) ENGINE=MYISAM;
{code}

Also we created a model class {{Application_Model_Users}} that extends {{Zend_Db_Table}}. So, very basic scaffolding initialization will look like this:

{code}
class UsersControllers extends Zend_Controller_Scaffolding
{
public function init() {
$this->initScaffolding(new Application_Model_Users());
}
}
{code}
{card}

{card:label=UC-2: advanced usage}
+Advanced usage with sorting, search, presentation tweaks, pagination.+
{code}
class UsersControllers extends Zend_Controller_Scaffolding
{
public function init() {
$fields = array(
'id' => array(
'skip' => 'list' // do not show PK
),
'username' => array(
'title' => 'Login',
'validators' => array(''),
'filters' => array('StripTags'),
'sortable' => true,
'required' => true
),
'password' => array(
'title' => Password',
'required' => true,
'skip' => 'list', // do not show passwords
'saveModifier'=> 'md5' // apply {{md5}} before save
),
'created_at' => array(
'title' => 'Created',
'skip' => 'edit', // do not allow to edit
'searchable' => true, // allow to search by creation date
'sortable' => true
)
);

$options = array(
'pagination' => true, // pagination with default options
'entityTitle' => 'user' // entity identification string, optional
'viewFolder' => 'users' // use custom path to view scripts
// do not allow modifications (readonly mode)
// 'readonly' => true
// disable deletion action
// 'disabled_actions' => array(self::ACTION_DELETE)
);

$this->initScaffolding(new Application_Model_Users(), $fields, $options);
}
}
{code}
{card}

{card:label=UC-3: list filtering}
+List filtering (using {{Zend_Db_Table_Select}}). Useful for simple reporting.+
{code}
class UsersControllers extends Zend_Controller_Scaffolding
{
public function init() {
// $this->_fields and $this->_options initialized
}

public function lasthourusersAction() {
$users = new Application_Model_Users();
// Users created during last hour
$select = $users->select()
->where('created_dt > DATE_SUB(NOW(), INTERVAL 1 HOUR)');
$this->initScaffolding($select, $this->_fields, $this->_options);
// Delegate to parent's index (listing) action
parent::indexAction();
}
}
{code}
{card}

{card:label=UC-4: handling relations}
+Handling table relations (1-N, N-N).+
Suppose we have two tables: Readers and Books. Each reader can read one or more books, and each book can be read by many readers.
Also, we want to handle this many-to-many relationship in this way: when registering a new reader we want to assign him immediately
one or more books. We need to do the following:
{code}
// Model setup
class Application_Model_ReadersBooks extends Zend_Db_Table
{
protected $_name = 'readers_books';

protected $_referenceMap = array(
'Reader' => array(
'columns' => 'reader_id', // foreign key column
'refTableClass' => 'Application_Model_Readers',
'refColumns' => 'id'
),
'Books' => array(
'columns' => 'book_id', // foreign key column
'refTableClass' => 'Application_Model_Books',
'refColumns' => 'id'
),
);
}

// Controller setup (fields definitions affected only)
class ReadersControllers extends Zend_Controller_Scaffolding
{
public function init() {
$fields = array(
// ... other fields
'books' => array(
'title' => 'Assign books',
'dependentTable' => new Application_Model_ReadersBooks(),
'type' => 'multicheckbox',
'skip' => 'list',
'required' => false
)
);
// other initialization options and initScaffolding call (see UC-1)
// ...
}
}

// Books model class
class Application_Model_Books extends Zend_Db_Table
{
protected $_name = 'books';

// This member specifies a field used to display
// a related entity instead of primary key (when assigning books to readers
// this will be the book identifying checkbox/option)
public $titleField = 'name';
}
{code}
{card}
{deck}
{composition-setup}
{zone-data}

{zone-data:skeletons}
{code}
class Zend_Controller_Scaffolding extends Zend_Controller_Action {
public function initScaffolding() {
}

public function indexAction() {
}

public function listAction() {
}

public function createAction() {
}

public function updateAction() {
}

public function deleteAction() {
}
}
{code}
{note:title=View scripts}
View scripts for corresponding actions will be available. User will have to place them under /views/scripts/scaffolding.
{note}
{zone-data}

{zone-template-instance}]]></ac:plain-text-body></ac:macro>