1. Zend Framework
“at your service”
Michelangelo van Dam
Dutch PHP Conference 2011 Amsterdam (NL)
2. Why a service ?
•- opening up existing API
internal applications
- external applications
- additional functionality
• support to more devices
• portability and flexibility
4. Example service
•- Time registration
list time sheets
- add a new task
- edit an existing task
- delete an existing task
5. MVC approach
•- time module
controllers (for displaying listing and forms)
- actions (for listing, adding, editing and deleting)
- models (for access to database)
- forms (for filtering, validation and rendering forms)
6. Common behavior
• all “logic” is put in the controller
• actions = API interface
•- downside
not flexible towards other clients
- difficult to provide maintenance
- not reusable design
7. Time Module
Time_IndexController
indexAction editAction
- lists registered tasks - displays a form
- links to the form - for adding task
- for adding task - for editing task
- for editing task
- for deleting task
registerAction deleteAction
- processes form data - deletes task
- validating data
- storing data in db
8. API Design
•- moving logic
out the controller
- in an API class
• structures the application
• is better testable
• is better maintainable
9. Time API
My_Api_Timesheet
listTasks registerNewTask
- lists registered tasks - for adding task
editExistingTask deleteExistingTask
- for modifying task - deletes task
15. listTasks
/**
* List all tasks for a given user
*
* @param int $user
* @return array
*/
public function listTasks($user)
{
$array = array ();
$timesheet = new Time_Model_Timesheet();
if (null !== ($result = $timesheet->fetchAll(array (
'user_id = ?' => $user,
), array ('date DESC', 'start_time ASC')))) {
foreach ($result as $entry) {
$array[] = $entry->toArray();
}
}
return $array;
}
16. registerNewTask
/**
* Register a new task
*
* @param int $user The ID of the user
* @param int $customer The ID of the customer
* @param int $task The ID of the task
* @param string $date A date formatted as YYYY-mm-dd
* @param string $start The starting time as HH:mm:ss
* @param string $end The ending time as HH:mm:ss
* @param string $description A short description
* @return bool TRUE if registration succeeded
* @throws My_Api_Timesheet_Exception
*/
17. registerNewTask
public function registerNewTask(
$user, $customer, $task, $date, $start, $end, $description)
{
$timesheet = new Time_Model_Timesheet();
$timesheet->setUserId($user)
->setCustomerId($customer)
->setTaskId($task)
->setDate($date)
->setStartTime($start)
->setEndTime($end)
->setDescription($description);
$validator = $this->_validate($timesheet);
if (false === $validator) {
require_once 'My/Api/Timesheet/Exception.php';
throw new My_Api_Timesheet_Exception('Invalid data provided');
}
$timesheet->save();
return true;
}
18. editExistingTask
/**
* Modify an existing task
*
* @param int $id The ID of an existing Task
* @param int $user The ID of the user
* @param int $customer The ID of the customer
* @param int $task The ID of the task
* @param string $date A date formatted as YYYY-mm-dd
* @param string $start The starting time as HH:mm:ss
* @param string $end The ending time as HH:mm:ss
* @param string $description A short description
* @return bool TRUE if registration succeeded
* @throws My_Api_Timesheet_Exception
*/
19. editExistingTask
public function editExistingTask(
$id, $user, $customer, $task, $date, $start, $end, $description)
{
$timesheet = new Time_Model_Timesheet();
$timesheet->setId($id)
->setUserId($user)
->setCustomerId($customer)
->setTaskId($task)
->setDate($date)
->setStartTime($start)
->setEndTime($end)
->setDescription($description);
$validator = $this->_validate($timesheet);
if (false === $validator) {
require_once 'My/Api/Timesheet/Exception.php';
throw new My_Api_Timesheet_Exception('Invalid data provided');
}
$timesheet->save();
return true;
}
20. deleteExistingTask
/**
* Modify an existing task
*
* @param int $id The ID of an existing Task
* @param int $user The ID of the user
* @return bool TRUE if registration succeeded
* @throws My_Api_Timesheet_Exception
*/
public function deleteExistingTask($id, $user)
{
$timesheet = new Time_Model_Timesheet();
$timesheet->setId($id)
->setUserId($user);
$validator = $this->_validate($timesheet);
if (false === $validator) {
require_once 'My/Api/Timesheet/Exception.php';
throw new My_Api_Timesheet_Exception('Invalid data provided');
}
$timesheet->delete(array (
'id = ?' => $timesheet->getId(),
'user_id = ?' => $timesheet->getUserId(),
));
return true;
}
21. _validate
/**
* Private validation method
*
* @param Time_Model_Timesheet $timesheet
* @return bool TRUE if validated, FALSE if invalid
*/
private function _validate(Time_Model_Timesheet $timesheet)
{
$result = true;
$validator = new Time_Form_Register();
$customer = new Time_Model_Customer();
$task = new Time_Model_Task();
$validator->getElement('customer_id')->setMultiOptions($customer->toSelect());
$validator->getElement('task_id')->setMultiOptions($task->toSelect());
if (!$validator->isValid($timesheet->toArray())) {
$result = false;
}
return $result;
}
28. REST Server
<?php
class Time_RestController extends Zend_Controller_Action
{
public function indexAction()
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
$server = new Zend_Rest_Server();
$server->setClass('My_Api_Timesheet');
$server->handle();
}
}
29. REST Client
<?php
class Time_RestClientController extends Zend_Controller_Action
{
protected $_client;
public function init()
{
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
$this->_client = new Zend_Rest_Client('http://www.demo.local/Time/rest');
}
public function indexAction()
{
$this->_client->listTasks(2);
Zend_Debug::dump($this->_client->get());
}
}
32. You can help !
•- find a bug ?
test it
- report it
- send a patch/fix
• need a non-existing component
- submit proposal
• like Zend Framework
- blog about it
- talk about it
33. ZF Bug hunt days
Zend Framework Bughuntdays
every 3rd Thursday and Friday of the month
http://framework.zend.com/issues
IRC (irc.freenode.net) #zftalk.dev
prizes:
Free subscription for 1 year on php|Architect magazine
Zend Framework t-shirt
recognition and appreciation of the community