SlideShare ist ein Scribd-Unternehmen logo
1 von 37
Zend Framework
“at your service”
       Michelangelo van Dam
 Dutch PHP Conference 2011 Amsterdam (NL)
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 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
API Design
•- moving logic
    out the controller
 - in an API class
• structures the application
• is better testable
• is better maintainable
Time API
                My_Api_Timesheet
 listTasks                  registerNewTask
- lists registered tasks   - for adding task




 editExistingTask           deleteExistingTask
- for modifying task       - deletes task
Simple ?
API output channels
 Web    Internal    SOAP




 XML    API        XMLRPC




 JSON     …         REST
Timesheet API
DocBlocks are important!
•- DocBlocks are very important !
     provide quality API documentation
 -   can be used as reference for the server !!!
My_Api_Timesheet
   <?php
class My_Api_Timesheet
{
}
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;
}
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
 */
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;
}
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
*/
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;
}
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;
}
_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
  <?php
class 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();
    }
}
Zend_Soap
SOAP Server
  <?php
class 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
      <?php
class 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()
    {
    	 Zend_Debug::dump($this->_client->listTasks(2));
    }
    public 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
  <?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();
    }
}
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 controller
          into a library API
                   =
              saves time

1 api = XmlRpc + SOAP + REST + …
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
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
ZF issue tracker
phpbenelux.eu


 PHP
 BENELUX
daycamp4developers.com
Project Management
    Late August - Early September
Thank you !


  Slides on Slideshare


Give feedback on Joind.in
   http://joind.in/3473

Weitere ähnliche Inhalte

Was ist angesagt?

The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICKonstantin Kudryashov
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsRoss Tuck
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Leonardo Proietti
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsSam Hennessy
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome TownRoss Tuck
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosDivante
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needKacper Gunia
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteLeonardo Proietti
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016Kacper Gunia
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingSamuel ROZE
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm OldRoss Tuck
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介Jace Ju
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneRafael Felix da Silva
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsŁukasz Chruściel
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Kacper Gunia
 
Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Vladyslav Riabchenko
 

Was ist angesagt? (20)

The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5Rich domain model with symfony 2.5 and doctrine 2.5
Rich domain model with symfony 2.5 and doctrine 2.5
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
 
Why is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenariosWhy is crud a bad idea - focus on real scenarios
Why is crud a bad idea - focus on real scenarios
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
Frontin like-a-backer
Frontin like-a-backerFrontin like-a-backer
Frontin like-a-backer
 
Symfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il clienteSymfony2, creare bundle e valore per il cliente
Symfony2, creare bundle e valore per il cliente
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event Sourcing
 
The IoC Hydra
The IoC HydraThe IoC Hydra
The IoC Hydra
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm Old
 
購物車程式架構簡介
購物車程式架構簡介購物車程式架構簡介
購物車程式架構簡介
 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com Backbone
 
Symfony World - Symfony components and design patterns
Symfony World - Symfony components and design patternsSymfony World - Symfony components and design patterns
Symfony World - Symfony components and design patterns
 
Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!Forget about index.php and build you applications around HTTP!
Forget about index.php and build you applications around HTTP!
 
Ruby - Design patterns tdc2011
Ruby - Design patterns tdc2011Ruby - Design patterns tdc2011
Ruby - Design patterns tdc2011
 
Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3Injection de dépendances dans Symfony >= 3.3
Injection de dépendances dans Symfony >= 3.3
 

Andere mochten auch

2012 Confoo: Defining User Identity
2012 Confoo: Defining User Identity2012 Confoo: Defining User Identity
2012 Confoo: Defining User IdentityJonathan LeBlanc
 
Dealing with Continuous Data Processing, ConFoo 2012
Dealing with Continuous Data Processing, ConFoo 2012Dealing with Continuous Data Processing, ConFoo 2012
Dealing with Continuous Data Processing, ConFoo 2012Michael Peacock
 
Paraccel/Database Architechs Press Release
Paraccel/Database Architechs Press ReleaseParaccel/Database Architechs Press Release
Paraccel/Database Architechs Press ReleaseDatabase Architechs
 
HTML5 et JS accessible mission impossible
HTML5 et JS accessible mission impossibleHTML5 et JS accessible mission impossible
HTML5 et JS accessible mission impossiblelevy aurélien
 
LemonLDAP::NG, un WebSSO libre (ConFoo 2011)
LemonLDAP::NG, un WebSSO libre (ConFoo 2011)LemonLDAP::NG, un WebSSO libre (ConFoo 2011)
LemonLDAP::NG, un WebSSO libre (ConFoo 2011)Clément OUDOT
 
In The Shadow Of The Ninja
In The Shadow Of The NinjaIn The Shadow Of The Ninja
In The Shadow Of The Ninjazburnham
 
Doctrine In The Real World sflive2011 Paris
Doctrine In The Real World sflive2011 ParisDoctrine In The Real World sflive2011 Paris
Doctrine In The Real World sflive2011 ParisJonathan Wage
 

Andere mochten auch (8)

2012 Confoo: Defining User Identity
2012 Confoo: Defining User Identity2012 Confoo: Defining User Identity
2012 Confoo: Defining User Identity
 
Dealing with Continuous Data Processing, ConFoo 2012
Dealing with Continuous Data Processing, ConFoo 2012Dealing with Continuous Data Processing, ConFoo 2012
Dealing with Continuous Data Processing, ConFoo 2012
 
Paraccel/Database Architechs Press Release
Paraccel/Database Architechs Press ReleaseParaccel/Database Architechs Press Release
Paraccel/Database Architechs Press Release
 
HTML5 et JS accessible mission impossible
HTML5 et JS accessible mission impossibleHTML5 et JS accessible mission impossible
HTML5 et JS accessible mission impossible
 
LemonLDAP::NG, un WebSSO libre (ConFoo 2011)
LemonLDAP::NG, un WebSSO libre (ConFoo 2011)LemonLDAP::NG, un WebSSO libre (ConFoo 2011)
LemonLDAP::NG, un WebSSO libre (ConFoo 2011)
 
Advanced CouchDB phpday.it
Advanced CouchDB phpday.itAdvanced CouchDB phpday.it
Advanced CouchDB phpday.it
 
In The Shadow Of The Ninja
In The Shadow Of The NinjaIn The Shadow Of The Ninja
In The Shadow Of The Ninja
 
Doctrine In The Real World sflive2011 Paris
Doctrine In The Real World sflive2011 ParisDoctrine In The Real World sflive2011 Paris
Doctrine In The Real World sflive2011 Paris
 

Ähnlich wie Zend Framework API Service Design

WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf Conference
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersKacper Gunia
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperGary Hockin
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From IusethisMarcus Ramberg
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Shinya Ohyanagi
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Elena Kolevska
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hackingJeroen van Dijk
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ EtsyNishan Subedi
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of LithiumNate Abele
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
Easy rest service using PHP reflection api
Easy rest service using PHP reflection apiEasy rest service using PHP reflection api
Easy rest service using PHP reflection apiMatthieu Aubry
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormMichelangelo van Dam
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On RailsJohn Wilker
 

Ähnlich wie Zend Framework API Service Design (20)

WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
 
PHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4Developers
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
ZF2 for the ZF1 Developer
ZF2 for the ZF1 DeveloperZF2 for the ZF1 Developer
ZF2 for the ZF1 Developer
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From Iusethis
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5Bootstrat REST APIs with Laravel 5
Bootstrat REST APIs with Laravel 5
 
Framework
FrameworkFramework
Framework
 
WordPress REST API hacking
WordPress REST API hackingWordPress REST API hacking
WordPress REST API hacking
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Easy rest service using PHP reflection api
Easy rest service using PHP reflection apiEasy rest service using PHP reflection api
Easy rest service using PHP reflection api
 
Quality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStormQuality assurance for php projects with PHPStorm
Quality assurance for php projects with PHPStorm
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On Rails
 

Mehr von Michelangelo van Dam

GDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and defaultGDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and defaultMichelangelo van Dam
 
Moving from app services to azure functions
Moving from app services to azure functionsMoving from app services to azure functions
Moving from app services to azure functionsMichelangelo van Dam
 
General Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's storyGeneral Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's storyMichelangelo van Dam
 
Leveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageLeveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageMichelangelo van Dam
 
Open source for a successful business
Open source for a successful businessOpen source for a successful business
Open source for a successful businessMichelangelo van Dam
 
Decouple your framework now, thank me later
Decouple your framework now, thank me laterDecouple your framework now, thank me later
Decouple your framework now, thank me laterMichelangelo van Dam
 
Deploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutesDeploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutesMichelangelo van Dam
 
Azure and OSS, a match made in heaven
Azure and OSS, a match made in heavenAzure and OSS, a match made in heaven
Azure and OSS, a match made in heavenMichelangelo van Dam
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your projectMichelangelo van Dam
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsMichelangelo van Dam
 
Easily extend your existing php app with an api
Easily extend your existing php app with an apiEasily extend your existing php app with an api
Easily extend your existing php app with an apiMichelangelo van Dam
 

Mehr von Michelangelo van Dam (20)

GDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and defaultGDPR Art. 25 - Privacy by design and default
GDPR Art. 25 - Privacy by design and default
 
Moving from app services to azure functions
Moving from app services to azure functionsMoving from app services to azure functions
Moving from app services to azure functions
 
Privacy by design
Privacy by designPrivacy by design
Privacy by design
 
DevOps or DevSecOps
DevOps or DevSecOpsDevOps or DevSecOps
DevOps or DevSecOps
 
Privacy by design
Privacy by designPrivacy by design
Privacy by design
 
Continuous deployment 2.0
Continuous deployment 2.0Continuous deployment 2.0
Continuous deployment 2.0
 
Let your tests drive your code
Let your tests drive your codeLet your tests drive your code
Let your tests drive your code
 
General Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's storyGeneral Data Protection Regulation, a developer's story
General Data Protection Regulation, a developer's story
 
Leveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageLeveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantage
 
The road to php 7.1
The road to php 7.1The road to php 7.1
The road to php 7.1
 
Open source for a successful business
Open source for a successful businessOpen source for a successful business
Open source for a successful business
 
Decouple your framework now, thank me later
Decouple your framework now, thank me laterDecouple your framework now, thank me later
Decouple your framework now, thank me later
 
Deploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutesDeploy to azure in less then 15 minutes
Deploy to azure in less then 15 minutes
 
Azure and OSS, a match made in heaven
Azure and OSS, a match made in heavenAzure and OSS, a match made in heaven
Azure and OSS, a match made in heaven
 
Getting hands dirty with php7
Getting hands dirty with php7Getting hands dirty with php7
Getting hands dirty with php7
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your project
 
Create, test, secure, repeat
Create, test, secure, repeatCreate, test, secure, repeat
Create, test, secure, repeat
 
The Continuous PHP Pipeline
The Continuous PHP PipelineThe Continuous PHP Pipeline
The Continuous PHP Pipeline
 
PHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the testsPHPUnit Episode iv.iii: Return of the tests
PHPUnit Episode iv.iii: Return of the tests
 
Easily extend your existing php app with an api
Easily extend your existing php app with an apiEasily extend your existing php app with an api
Easily extend your existing php app with an api
 

Kürzlich hochgeladen

Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfpanagenda
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Mark Goldstein
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersRaghuram Pandurangan
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Scott Andery
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxLoriGlavin3
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024Lonnie McRorey
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditSkynet Technologies
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfMounikaPolabathina
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rick Flair
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demoHarshalMandlekar2
 

Kürzlich hochgeladen (20)

Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdfSo einfach geht modernes Roaming fuer Notes und Nomad.pdf
So einfach geht modernes Roaming fuer Notes und Nomad.pdf
 
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
Arizona Broadband Policy Past, Present, and Future Presentation 3/25/24
 
Generative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information DevelopersGenerative AI for Technical Writer or Information Developers
Generative AI for Technical Writer or Information Developers
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
 
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptxDigital Identity is Under Attack: FIDO Paris Seminar.pptx
Digital Identity is Under Attack: FIDO Paris Seminar.pptx
 
TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024TeamStation AI System Report LATAM IT Salaries 2024
TeamStation AI System Report LATAM IT Salaries 2024
 
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Manual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance AuditManual 508 Accessibility Compliance Audit
Manual 508 Accessibility Compliance Audit
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
What is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdfWhat is DBT - The Ultimate Data Build Tool.pdf
What is DBT - The Ultimate Data Build Tool.pdf
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...Rise of the Machines: Known As Drones...
Rise of the Machines: Known As Drones...
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
Sample pptx for embedding into website for demo
Sample pptx for embedding into website for demoSample pptx for embedding into website for demo
Sample pptx for embedding into website for demo
 

Zend Framework API Service Design

  • 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
  • 3. 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
  • 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
  • 11. API output channels Web Internal SOAP XML API XMLRPC JSON … REST
  • 13. DocBlocks are important! •- DocBlocks are very important ! provide quality API documentation - can be used as reference for the server !!!
  • 14. My_Api_Timesheet <?php class My_Api_Timesheet { }
  • 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; }
  • 23. XmlRpc Server <?php class 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(); } }
  • 25. SOAP Server <?php class 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(); } }
  • 26. SOAP Client <?php class 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() { Zend_Debug::dump($this->_client->listTasks(2)); } public 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)); } }
  • 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()); } }
  • 31. Conclusion moving functionality out the controller into a library API = saves time 1 api = XmlRpc + SOAP + REST + …
  • 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
  • 36. daycamp4developers.com Project Management Late August - Early September
  • 37. Thank you ! Slides on Slideshare Give feedback on Joind.in http://joind.in/3473

Hinweis der Redaktion

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n