introduction to zend framework web services
Post on 20-Aug-2015
7.010 Views
Preview:
TRANSCRIPT
Zend Framework “at your service”
Michelangelo van DamMacq Electronique 2010, Brussels
WARNING
Used EnvironmentPHP 5.3.2
Zend Framework 1.10.4MySQL 5.1.32
Examples might not work on another environment
Michelangelo van Dam
• Independent Consultant
• Zend Certified Engineer (ZCE)
- PHP 4 & PHP 5
- Zend Framework• Co-Founder of PHPBenelux• Shepherd of “elephpant” herds
What is Zend Framework
A loosly-coupled framework with a flexible architecture that lets you easily build modern web applications and web servicesMatthew Weier O’Phinney - Chief Architect Zend Framework
Why a service ?
• opening up existing API- internal applications- external applications- additional functionality• support to more devices• portability and flexibility
Important components
• Zend_Soap- Zend_Soap_Server- Zend_Soap_Client- Zend_Soap_Wsdl• Zend_Rest- Zend_Rest_Server- Zend_Rest_Client• Zend_XmlRpc- Zend_XmlRpc_Server- Zend_XmlRpc_Client- Zend_XmlRpc_Request- Zend_XmlRpc_Response
Example service
• Time registration- list time sheets- add a new task- edit an existing task- delete an existing task
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)
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
Time_IndexController
Time ModuleindexAction
- lists registered tasks- links to the form - for adding task - for editing task - for deleting task
editAction- displays a form - for adding task - for editing task
registerAction- processes form data - validating data - storing data in db
deleteAction- deletes task
API Design
• moving logic- out the controller- in an API class• structures the application• is better testable• is better maintainable
My_Api_Timesheet
Time APIlistTasks
- lists registered tasksregisterNewTask
- for adding task
editExistingTask- for modifying task
deleteExistingTask- deletes task
Simple ?
API output channels
API
Web
XML
SOAP
XMLRPC
Internal
JSON … REST
Timesheet API
DocBlocks are important!
• DocBlocks are very important !- provide quality API documentation- can be used as reference for the service !!!
Automated API docs
My_Api_Timesheet<?phpclass My_Api_Timesheet{}
listTasks/** * List all tasks for a given user * * @param int $user * @param int $limit * @return array */public function listTasks($user, $limit = null){ $array = array (); $timesheet = new Time_Model_Timesheet(); if (null !== ($result = $timesheet->fetchAll(array ( 'user_id = ?' => $user, ), array ('date DESC', 'start_time ASC'), $limit))) { foreach ($result as $entry) { $array[] = $entry->toArray(); } } return $array;}
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 */
registerNewTaskpublic 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;}
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 */
editExistingTaskpublic 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;}
deleteExistingTask/** * Removes 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 */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;}
_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;}
Zend_XmlRpc
XmlRpc Server<?phpclass Time_XmlRpcController extends Zend_Controller_Action{ public function indexAction() { $this->_helper->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); require_once 'My/Api/Timesheet.php'; $server = new Zend_XmlRpc_Server(); $server->setClass('My_Api_Timesheet'); echo $server->handle(); }}
XmlRpc Client<?phpclass Time_XmlRpcClientController extends Zend_Controller_Action{ protected $_client; public function init() { $this->_helper->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); $this->_client = new Zend_XmlRpc_Client( 'http://www.demo.local/Time/XmlRpc'); }…}
XmlRpc Clientpublic function newAction(){ $client = $this->_client; $request = new Zend_XmlRpc_Request(); $request->setMethod('registerNewTask'); $request->setParams(array ( 2, // user ID 3, // customer ID 3, // task ID '2010-03-28', // date '18:00:00', // start time '23:30:00', // end time 'Demo XmlRpc add', // description )); $result = null; $errors = array (); try { $client->doRequest($request); $result = $client->getLastResponse()->getReturnValue(); } catch (Zend_XmlRpc_Client_FaultException $e) { $errors['fault'] = "[{$e->getCode()}]: {$e->getMessage()}"; } catch (Zend_XmlRpc_Client_HttpException $e) { $errors['http'] = "[{$e->getCode()}]: {$e->getMessage()}"; } catch (My_Api_Timesheet_Exception $e) { $errors['api'] = "[{$e->getCode()}]: {$e->getMessage()}"; }}
XmlRpc Clientpublic function editAction(){ $client = $this->_client; $request = new Zend_XmlRpc_Request(); $request->setMethod('editExistingTask'); $request->setParams(array ( 5, // ID 2, // user ID 3, // customer ID 4, // task ID '2010-03-28', // date '18:00:00', // start time '23:30:00', // end time 'Demo XmlRpc add', // description )); $result = null; $errors = array (); try { $client->doRequest($request); $result = $client->getLastResponse()->getReturnValue(); } catch (Zend_XmlRpc_Client_FaultException $e) { $errors['fault'] = "[{$e->getCode()}]: {$e->getMessage()}"; } catch (Zend_XmlRpc_Client_HttpException $e) { $errors['http'] = "[{$e->getCode()}]: {$e->getMessage()}"; } catch (My_Api_Timesheet_Exception $e) { $errors['api'] = "[{$e->getCode()}]: {$e->getMessage()}"; }}
XmlRpc Clientpublic function deleteAction(){ $client = $this->_client; $request = new Zend_XmlRpc_Request(); $request->setMethod('deleteExistingTask'); $request->setParams(array ( 6, // ID 2, // user ID )); $result = null; $errors = array (); try { $client->doRequest($request); $result = $client->getLastResponse()->getReturnValue(); if ($client->getLastResponse()->isFault()) { $result = $client->getLastResponse()->getFault(); } } catch (Zend_XmlRpc_Client_FaultException $e) { $errors['fault'] = "[{$e->getCode()}]: {$e->getMessage()}"; } catch (Zend_XmlRpc_Client_HttpException $e) { $errors['http'] = "[{$e->getCode()}]: {$e->getMessage()}"; } catch (My_Api_Timesheet_Exception $e) { $errors['api'] = "[{$e->getCode()}]: {$e->getMessage()}"; }}
Zend_Soap
SOAP Server<?phpclass Time_SoapController extends Zend_Controller_Action{ public function indexAction() { $this->_helper->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); $options = array (); $server = new Zend_Soap_AutoDiscover(); $server->setClass('My_Api_Timesheet'); $server->handle(); }}
SOAP Client<?phpclass Time_SoapClientController extends Zend_Controller_Action{ protected $_client; public function init() { $this->_helper->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); $this->_client = new Zend_Soap_Client( 'http://www.demo.local/Time/soap?wsdl', array ()); }
public function indexAction() { $result = $this->_client->listTasks(2, 2); $this->getResponse()->setHeader('Content-Type', 'text/xml; Charset=UTF-8'); echo $this->_client->getLastResponse(); }…
SOAP Clientpublic function addAction() { Zend_Debug::dump($this->_client->registerNewTask( 2, 2, 3, '2010-03-30', '18:00:00', '23:30:00','Setting up SOAP')); } public function editAction() { Zend_Debug::dump($this->_client->editExistingTask( 7, 2, 2, 3, '2010-03-30', '18:00:00', '23:30:00','Testing SOAP')); } public function deleteAction() { Zend_Debug::dump($this->_client->deleteExistingTask(7, 2)); }}
Zend_Rest
REST Server<?phpclass 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(); }}
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()); }}
Patterns ???
Conclusion
moving functionality out the controllerinto a library API
=saves time
1 api = XmlRpc + SOAP + REST + …
Recommended readingWeb Services EssentialsEthan Cerami
O’Reilly
Programming Web Services with XML-RPCSimon St. Laurent, Joe Johnston, Edd Dumbill, Dave Winer
O’Reilly
Recommended readingRESTful Web ServicesLeonard Richardson, Sam Ruby
O’Reilly
Programming Web Services with XML-RPCJames Snell, Doug Tidwell, Pavel Kulchenko
O’Reilly
We need you help !!!
Feedback is important
• 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• translations
ZF Bug hunt days
Zend Framework Bughuntdaysevery 3rd Thursday and Friday of the month
http://framework.zend.com/issuesIRC (irc.freenode.net) #zftalk.dev
prizes:recognition and appreciation of the community
Free subscription for 1 year on php|Architect magazineZend Framework t-shirt
ZF issue tracker
• When: June 10 - 12 2010• Where: Amsterdam RAI• Tickets: http://phpconference.nl• Early bird: ends April 30, 2010 (Queen’s Day)
• annual event• improve code coverage• test php core source code• improve quality of PHP
PHPB ENELUX
• When: May 29, 2010• Where: <to-be-defined>• Updates: • web: http://www.phpbenelux.eu• twitter: @phpbenelux
PHPB ENELUX
Thank you !
Slides on Slidesharehttp://www.slideshare.net/group/macqel
Give feedback on Joind.inhttp://joind.in/1263
top related