D. Blocks

A block is a piece of configurable output that can be reused across different templates and applications. When we talk about a post model for example, we can already think to create a form, list and detail template. There are two parts to a block. The first one is the configuration class where it's goal is to provide the template all the necessary variables it needs to output. The second one is the actual template. Though when we think about template, it's usually in HTML, but often it could also be XML, JSON, query, image data, so we have to keep blocks very flexible.

Lets first start with a post list block. Inside module/post make a new folder called block and in that folder, a file called list.php and paste Figure 15.

Figure 15. list.php
<?php //-->
class Post_Block_List extends Eden_Block {
	/* Constants
	-------------------------------*/
	/* Public Properties
	-------------------------------*/
	/* Protected Properties
	-------------------------------*/
	protected $_columns		= array(
		'post_id'		=> 'ID', 
		'post_title'	=> 'Title', 
		'post_active'	=> 'Detail', 
		'post_created'	=> 'Created', 
		'post_updated'	=> 'Updated');
		
	protected $_collection 	= NULL;
	
	/* Private Properties
	-------------------------------*/
	/* Magic
	-------------------------------*/
	public function __construct(Post_Collection $collection) {
		$this->_collection = $collection;
	}
	
	/* Public Methods
	-------------------------------*/
	/**
	 * Allow to redefine columns
	 *
	 * @param array
	 * @return this
	 */
	public function setColumns(array $columns) {
		$this->_columns = $columns;
		return $this;
	}
	
	/**
	 * Returns the template variables in key value format
	 *
	 * @param array data
	 * @return array
	 */
	public function getVariables() {
		return array(
			'columns' 		=> $this->_columns,
			'collection'	=> $this->_collection);
	}
	
	/**
	 * Returns a template file
	 * 
	 * @param array data
	 * @return string
	 */
	public function getTemplate() {
		return realpath(dirname(__FILE__).'/list.phtml');
	}
	
	/* Protected Methods
	-------------------------------*/
	/* Private Methods
	-------------------------------*/
}

When we extend Eden_Block we need to define getVariables() and getTemplate() as a requirement. We separated these two methods to what they are for flexibility. For instances, you can provide your own logic to form the variables and reuse the block template or you can reuse the block formed variables and use a different template. Figure 16 shows how we can easily change out block parts without extending.

Figure 16. Interchanging template file and variables
$file = __DIR__.'/custom_list.phtml';
$data = front()->Post_Block_List()->getVariables();
echo front()->template($file, $data);

//----OR----//

$file = front()->Post_Block_List()->getTemplate();
$data = array('collection' => $customCollection, 'columns' => $customColumns);
echo front()->template($file, $data);

Going back to Figure 15, we also defined a custom method which will control the column header label and
order. Block methods can be freely defined as you need them. The more available options you define, the more powerful your block becomes. Next create another file in module/post/block called list.phtml and paste Figure 17.

Figure 17. list.phtml
<table>
	<thead>
		<tr>
			<?php foreach($columns as $key => $label): ?>
			<th><?php echo $label; ?></th>
			<?php endforeach; ?>		
		</tr>
	</thead>
	<tbody>
		<?php foreach($collection as $model): ?>
		<tr>
			<?php foreach($columns as $key => $label): ?>
			<td><?php echo $model[$key]; ?></td>
			<?php endforeach; ?>	
		</tr>
		<?php endforeach; ?>
	</tbody>
</table>

Now that we have our block defined, open web/index.php and at the bottom paste in Figure 18.

Figure 18. Test Drive Post List
$collection = front()
	->Post_Search()
	->getCollection();

echo front()->Post_Block_List($collection)
	->setColumns(array(
	'post_id'		=> 'ID', 
	'post_title'	=> 'Title', 
	'post_created'	=> 'Created'));
Don't forget to remove Figure 18 from web/index.php when your done testing.

A harder example to portray is a post form block. We need to go through this example in order for you to truly understand why blocks are a powerful piece of flexible code. Create another file in module/post/block called form.php and paste Figure 19.

Figure 19. form.php
<?php //-->
class Post_Block_Form extends Eden_Block {
	/* Constants
	-------------------------------*/
	/* Public Properties
	-------------------------------*/
	/* Protected Properties
	-------------------------------*/
	protected $_data = array(
		'post_title'	=> NULL,
		'post_detail'	=> NULL);
	
	protected $_action 		= NULL;
	protected $_database 	= NULL;
	
	/* Private Properties
	-------------------------------*/
	/* Magic
	-------------------------------*/
	public function __construct(Eden_Sql_Database $database = NULL) {
		if(is_null($database)) {
			$database = Eden::i()->getActiveApp()->getDatabase();
		}
		
		$this->_database = $database;
	}
	
	/* Public Methods
	-------------------------------*/
	/**
	 * Return form errors
	 * 
	 * @return array
	 */
	public function getErrors() {
		$errors = array();
		if(isset($this->_data['post_title']) && !trim($this->_data['post_title'])) {
			$errors['post_title'] = 'Title cannot be empty.';
		}
		
		if(isset($this->_data['post_detail']) && !trim($this->_data['post_detail'])) {
			$errors['post_detail'] = 'Detail cannot be empty.';
		}
		
		return $errors;
	}
	
	/**
	 * Returns a template file
	 * 
	 * @param array data
	 * @return string
	 */
	public function getTemplate() {
		return dirname(__FILE__).'/form.phtml';
	}
	
	/**
	 * Returns the template variables in key value format
	 *
	 * @param array data
	 * @return array
	 */
	public function getVariables() {
		return array(
			'action' 	=> $this->_action, 
			'data' 		=> $this->_data,
			'errors' 	=> $this->getErrors());
	}
	
	/**
	 * Sets form action
	 *
	 * @param string
	 * @return this
	 */
	public function setAction($action) {
		$this->_action = $action;
		return $this;
	}
	
	/**
	 * Sets form data
	 *
	 * @param array
	 * @return this
	 */
	public function setData(array $data) {
		$this->_data = array_merge($this->_data, $data);
		return $this;
	}
	
	/**
	 * Process form to database
	 *
	 * @return this
	 */
	public function process() {
		if(empty($this->_data)) {
			return $this;
		}
		
		$model = $this->Post_Model()
			->setPostTitle($this->_data['post_title'])
			->setPostDetail($this->_data['post_detail'])
			->setPostUser(1);
		
		if(isset($this->_data['post_active'])) {
			$model->setPostActive($this->_data['post_active'] ? 1:0);
		}
		
		$model->insert();
		return $this;
	}
	
	/**
	 * Vaidates current data
	 * 
	 * @return bool
	 */
	public function valid() {
		$errors = $this->getErrors();
		return empty($errors);
	}
	
	/* Protected Methods
	-------------------------------*/
	/* Private Methods
	-------------------------------*/
}

Next create another file in module/post/block called form.phtml and paste Figure 20.

Figure 20. form.phtml
<form action="<?php echo $action; ?>" method="post">
	<fieldset>
		<legend>Create Post</legend>
		<div class="form-row">
			<label>Title</label>
			<div class="form-field">
				<?php if(isset($errors['post_title'])): ?>
				<div class="form-error"><?php echo $errors['post_title']; ?></div>
				<?php endif; ?>
				<input type="text" name="post_title" value="<?php echo $data['post_title']; ?>" />
			</div>
		</div>
		
		<div class="form-row">
			<label>Detail</label>
			<div class="form-field">
				<?php if(isset($errors['post_detail'])): ?>
				<div class="form-error"><?php echo $errors['post_detail']; ?></div>
				<?php endif; ?>
				<input type="text" name="post_detail" value="<?php echo $data['post_detail']; ?>" />
			</div>
		</div>
	</fieldset>
	<div class="form-row no-label">
		<div class="form-field">
			<input type="submit" value="Create" />
		</div>
	</div>
</form>

Now that we have our form block defined, open web/index.php and at the bottom paste in Figure 12.

Figure 12. Test Drive Post Form
<?php
$form = front()->Post_Block_Form();

if(!empty($_POST)) {
	$form->setData($_POST);
	if($form->valid()) {
		$form->process();
	}
}

echo $form;
?>
Don't forget to remove Figure 18 from web/index.php when your done testing.

© 2012 Openovate Labs. All rights reserved.