AAPPIIGGIILLIITTYY 
Heute klicken wir unsere API einfach mal zusammen... 
 
1 / 54
ÜÜbbeerr RRaallff EEggggeerrtt 
● PHP seit 1999 
● Zend Framework 2 
● Trainer 
● Berater 
● Autor 
● Insulaner 
2 / 54
[A] 
PPrroolloogg 
3 / 54
[1] 
Neue API 
in 2 Stunden? 
4 / 54
[2] 
5 / 54
[3] 
IInn aa NNuuttsshheellll 
6 / 54
RReessttffuull WWeebb SSeerrvviicceess 
CLIENT 
Web Browser 
PHP 
Javascript 
RUBY 
PYTHON 
REST SERVER 
/api/user/123 
/api/user 
/api/user 
/api/user/123 
/api/user/123 
USER DOMAIN 
getUserEntity() 
getUserCollection() 
addUserEntity() 
updateUserEntity() 
deleteUserEntity() 
GET Request 
JSON Response 
GET Request 
JSON Response 
POST Request 
JSON Response 
PUT Request 
JSON Response 
DELETE Request 
JSON Response 
Integer 
UserEntity 
void 
UserCollection 
Array 
Boolean 
Integer, Array 
Boolean 
Integer 
Boolean 
7 / 54
RRPPCC WWeebb SSeerrvviicceess 
Local 
CLIENT 
javascript 
RPC 
Client 
JSON 
Method:getUser 
Params:id 
USER DOMAIN 
getUserEntity() 
GET Request 
JSON Result 
Integer 
UserEntity 
RPC 
Server 
/json-rpc.php 
Remote Call 
JSON Result 
javascript 
JSON 
Method:addUser 
Params:name 
addUserEntity() 
POST Request 
JSON Result 
Array 
Boolean 
/json-rpc.php 
Remote Call 
JSON Result 
javascript 
XML 
Method:getUser 
Params:id 
getUserEntity() 
GET Request 
XML Result 
Integer 
UserEntity 
/xml-rpc.php 
Remote Call 
XML Result 
javascript 
XML 
Method:addUser 
Params:name 
addUserEntity() 
POST Request 
XML Result 
Array 
Boolean 
/xml-rpc.php 
Remote Call 
XML Result 
8 / 54
VVeerrssiioonniieerruunngg 
ddeeffaauulltt VVeerrssiioonn ppeerr UURRLL 
VVeerrssiioonn 11 ppeerr UURRLL 
VVeerrssiioonn 22 ppeerr UURRLL 
ddeeffaauulltt VVeerrssiioonn ppeerr CCoonntteenntt NNeeggoottiiaattiioonn 
VVeerrssiioonn 11 ppeerr CCoonntteenntt NNeeggoottiiaattiioonn 
VVeerrssiioonn 22 ppeerr CCoonntteenntt NNeeggoottiiaattiioonn 
9 / 54
JJSSOONN // HHAALL // PPrroobblleemm 
10 / 54
WWEEIITTEERREE FFEEAATTUURREESS 
[4, 5, 6, 7, 8, 9] 
DDaatteennbbaannkk--bbaassiieerrtt CCooddee--bbaassiieerrtt aauutthheennttiiffiizziieerruunngg 
AAPPII DDookkuummeennttaattiioonn DDaatteennvvaalliiddiieerruunngg DDeeppllooyymmeenntt 
11 / 54
MMoodduullaarriissiieerruunngg 
ZZff--aappiiggiilliittyy ZZff--aappiiggiilliittyy--aaddmmiinn ZZff--aappiiggiilliittyy--ddooccuummeennttaattiioonn 
ZZff--aappiiggiilliittyy--ddooccuummeennttaattiioonn--sswwaaggggeerr ZZff--aappiiggiilliittyy--pprroovviiddeerr ZZff--aappiiggiilliittyy--WWeellccoommee 
ZZff--aappii--pprroobblleemm ZZff--ccoonnffiigguurraattiioonn ZZff--ccoonntteenntt--nneeggoottiiaattiioonn 
ZZff--ccoonntteenntt--vvaalliiddaattiioonn ZZff--ddeeppllooyy ZZff--ddeevveellooppmmeenntt--mmooddee 
ZZff--hhaall ZZff--mmvvcc--aauutthh ZZff--ooaauutthh22 
ZZff--rreesstt ZZff--RRPPCC ZZff--vveerrssiioonniinngg 
12 / 54
IInnssttaallllaattiioonn 
Composer direkt 
$ curl -s https://getcomposer.org/installer | php -- 
$ php composer.phar create-project -sdev zfcampus/zf-apigility-skeleton /path/to/install 
$ cd /path/to/install 
Git und Composer 
$ git clone https://github.com/zfcampus/zf-apigility-skeleton.git /path/to/install 
$ cd /path/to/install 
$ php composer.phar install 
ZIP und Composer 
$ wget https://github.com/zfcampus/zf-apigility-skeleton/archive/master.zip 
$ unzip -d /path/to/install master.zip 
$ cd /path/to/install 
$ php composer.phar install 
Entwicklungsmodus einschalten und Rechte setzen 
$ php public/index.php development enable 
$ sudo chmod 777 -R config/ 
$ sudo chmod 777 -R data/ 
$ sudo chmod 777 -R module/ 
13 / 54
SSttaarrttsseeiittee 
14 / 54
[4] 
DDBB--bbaassiieerrtteerr 
RREESSTT--SSeerrvviiccee 
15 / 54
DDaatteennbbaannkkmmooddeellll 
16 / 54
DDaatteennbbaannkkaaddaapptteerr 
Schritte 1 bis 6 17 / 54
RReesstt SSeerrvviiccee,, DDBB--bbaassiieerrtt 
Schritte 1 bis 6 18 / 54
RReesstt SSeerrvviiccee,, DDBB--bbaassiieerrtt 
Schritte 7 bis 12 19 / 54
RReesstt SSeerrvviiccee,, DDBB--bbaassiieerrtt 
Schritte 13 bis 18 20 / 54
RREESSTT SSeerrvviiccee UUsseerr LLiissttee 
21 / 54
RREESSTT SSeerrvviiccee UUsseerr EEnnttiittyy 
22 / 54
[10] 
PPOOSSTT 
PPUUTT 
DDEELLEETTEE 
23 / 54
RReesstt SSeerrvviiccee PPoosstt II 
Schritte 1 bis 3 24 / 54
RReesstt SSeerrvviiccee PPoosstt IIII 
Schritte 4 bis 6 25 / 54
RReesstt SSeerrvviiccee PPuutt II 
Schritte 1 bis 3 26 / 54
RReesstt SSeerrvviiccee PPuutt IIII 
Schritt 4 27 / 54
RReesstt SSeerrvviiccee DDeelleettee 
Schritte 1 bis 3 28 / 54
[6] 
AAUUTTHHEENNTTIIFFII-- 
ZZIIEERRUUNNGG 
29 / 54
AAuutthheennttiiffiizziieerruunngg II 
HTTP BASIC HTTP DIGEST OAUTH2 
HTpasswd 
$ htpasswd -c data/htpasswd apigility 
New password: ********* 
Re-type new password: ********* 
Adding password for user apigility 
$ 
30 / 54
AAuutthheennttiiffiizziieerruunngg IIII 
Schritte 1 bis 6 31 / 54
AAuutthheennttiiffiizziieerruunngg IIIIII 
Schritt 7 32 / 54
AAuutthheennttiiffiizziieerruunngg IIVV 
Schritt 8 33 / 54
[5] 
CCooddee--bbaassiieerrtteerr 
RREESSTT SSEERRVVIICCEE 
34 / 54
RReesstt SSeerrvviiccee,, CCooddee--bbaassiieerrtt 
Schritte 1 bis 6 35 / 54
RReesstt SSeerrvviiccee,, CCooddee--bbaassiieerrtt 
Schritte 7 bis 12 36 / 54
[11] 
Was ist daran 
Code-basiert? 
37 / 54
GGeenneerriieerrttee DDaatteeiieenn 
Dateirechte setzen und Dateien anzeigen 
$ cd /home/devhost/apigility.local/ 
$ sudo chmod 777 -R module/User/src/User/V2 
$ ls -al module/User/src/User/V2/Rest/UserProfile/ 
drwxrwxrwx 2 www-data www-data 4096 Aug 30 21:39 . 
drwxrwxrwx 4 www-data www-data 4096 Aug 30 21:39 .. 
-rwxrwxrwx 1 www-data www-data 126 Aug 30 21:39 UserProfileCollection.php 
-rwxrwxrwx 1 www-data www-data 73 Aug 30 21:39 UserProfileEntity.php 
-rwxrwxrwx 1 www-data www-data 177 Aug 30 21:39 UserProfileResourceFactory.php 
-rwxrwxrwx 1 www-data www-data 2341 Aug 30 21:39 UserProfileResource.php 
Verzeichnis für table Gateway Klassen anlegen 
$ cd module/User/src/User/V2/Rest/UserProfile/ 
$ mkdir Table 
38 / 54
UUsseerr PPrrooffiillee eennttiittyy 
namespace UserV2RestUserProfile; 
class UserProfileEntity 
{ 
protected $id; 
protected $name; 
protected $email; 
protected $contacts; 
protected $websites; 
public function setId($id) {} 
public function getId() {} 
public function setName($name) {} 
public function getName() {} 
public function setEmail($email) {} 
public function getEmail() {} 
public function setContacts(array $contacts) {} 
public function getContacts() {} 
public function setWebsites(array $websites) {} 
public function getWebsites() {} 
} 
39 / 54
UUsseerr TTaabbllee II 
namespace UserV2RestUserProfileTable; 
use ZendDbAdapterAdapterInterface; 
use ZendDbResultSetResultSetInterface; 
use ZendDbTableGatewayTableGateway; 
class UserTable extends TableGateway 
{ 
public function __construct( 
AdapterInterface $adapter, 
ResultSetInterface $resultSetPrototype = null 
) { 
$table = 'users'; 
parent::__construct($table, $adapter, null, $resultSetPrototype); 
} 
public function fetchUserById($id) 
{ 
$select = $this->getSql()->select(); 
$select->where->equalTo('id', $id); 
return $this->selectWith($select)->current(); 
} 
[...] 
} 
40 / 54
UUsseerr TTaabbllee IIII 
namespace UserV2RestUserProfileTable; 
class UserTable extends TableGateway 
{ 
[...] 
public function fetchContactsById($id) 
{ 
$select = $this->getSql()->select(); 
$select->join('user_contacts', 'user_id_2 = id', array()); 
$select->where->equalTo('user_id_1', $id); 
return $this->selectWith($select)->toArray(); 
} 
public function fetchUsers($params) 
{ 
$select = $this->getSql()->select(); 
return $this->selectWith($select)->toArray(); 
} 
} 
41 / 54
UUsseerr TTaabbllee ffaaccttoorryy 
namespace UserV2RestUserProfileTable; 
use ZendDbResultSetResultSet; 
use ZendServiceManagerFactoryInterface; 
use ZendServiceManagerServiceLocatorInterface; 
class UserTableFactory implements FactoryInterface 
{ 
public function createService(ServiceLocatorInterface $serviceLocator) 
{ 
$dbAdapter = $serviceLocator->get('MysqlAdapter'); 
$resultSet = new ResultSet(ResultSet::TYPE_ARRAY); 
$table = new UserTable($dbAdapter, $resultSet); 
return $table; 
} 
} 
42 / 54
WWeebbssiittee TTaabbllee 
namespace UserV2RestUserProfileTable; 
use ZendDbAdapterAdapterInterface; 
use ZendDbResultSetResultSetInterface; 
use ZendDbTableGatewayTableGateway; 
class WebsiteTable extends TableGateway 
{ 
public function __construct( 
AdapterInterface $adapter, 
ResultSetInterface $resultSetPrototype = null 
) { 
$table = 'websites'; 
parent::__construct($table, $adapter, null, $resultSetPrototype); 
} 
public function fetchWebsitesById($id) 
{ 
$select = $this->getSql()->select(); 
$select->join('user_websites', 'website_id = id', array()); 
$select->where->equalTo('user_id', $id); 
return $this->selectWith($select)->toArray(); 
} 
} 
43 / 54
WWeebbssiittee FFaaccttoorryy 
namespace UserV2RestUserProfileTable; 
use ZendDbResultSetResultSet; 
use ZendServiceManagerFactoryInterface; 
use ZendServiceManagerServiceLocatorInterface; 
class WebsiteTableFactory implements FactoryInterface 
{ 
public function createService(ServiceLocatorInterface $serviceLocator) 
{ 
$dbAdapter = $serviceLocator->get('MysqlAdapter'); 
$resultSet = new ResultSet(ResultSet::TYPE_ARRAY); 
$table = new WebsiteTable($dbAdapter, $resultSet); 
return $table; 
} 
} 
44 / 54
UUsseerr PPrrooffiillee RReessoouurrccee II 
namespace UserV2RestUserProfile; 
use UserV2RestUserProfileTableUserTable; 
use UserV2RestUserProfileTableWebsiteTable; 
use ZFApiProblemApiProblem; 
use ZFRestAbstractResourceListener; 
class UserProfileResource extends AbstractResourceListener 
{ 
protected $userTable; 
protected $websiteTable; 
public function setUserTable($userTable) {} 
public function getUserTable() {} 
public function setWebsiteTable($websiteTable) {} 
public function getWebsiteTable() {} 
protected function addContactsAndWebsites(array $user) 
{ 
$user['contacts'] = $this->getUserTable()->fetchContactsById($user['id']); 
$user['websites'] = $this->getWebsiteTable()->fetchWebsitesById($user['id']); 
return $user; 
} 
[...] 
} 
45 / 54
UUsseerr PPrrooffiillee RReessoouurrccee IIII 
namespace UserV2RestUserProfile; 
class UserProfileResource extends AbstractResourceListener 
{ 
[...] 
public function create($data) 
{ 
return new ApiProblem(405, 'The POST method has not been defined'); 
} 
public function delete($id) {} 
public function deleteList($data) {} 
public function fetch($id) 
{ 
$user = $this->getUserTable()->fetchUserById($id); 
if (!$user) { 
return new ApiProblem(404, 'User profile for id ' . $id . ' not found'); 
} 
return $this->addContactsAndWebsites($user); 
} 
[...] 
} 
46 / 54
UUsseerr PPrrooffiillee RReessoouurrccee IIIIII 
namespace UserV2RestUserProfile; 
class UserProfileResource extends AbstractResourceListener 
{ 
[...] 
public function fetchAll($params = array()) 
{ 
$users = $this->getUserTable()->fetchUsers($params); 
if (!$users) { 
return new ApiProblem(404, 'No user profiles found'); 
} 
foreach ($users as $key => $user) { 
$users[$key] = $this->addContactsAndWebsites($user); 
} 
return $users; 
} 
public function patch($id, $data) {} 
public function replaceList($data) {} 
public function update($id, $data) {} 
} 
47 / 54
UUsseerr PPrrooffiillee RReessoouurrccee FFaaccttoorryy 
namespace UserV2RestUserProfile; 
class UserProfileResourceFactory 
{ 
public function __invoke($services) 
{ 
$userTable = $services->get( 
'UserV2RestUserProfileTableUserTable' 
); 
$websiteTable = $services->get( 
'UserV2RestUserProfileTableWebsiteTable' 
); 
$resource = new UserProfileResource(); 
$resource->setUserTable($userTable); 
$resource->setWebsiteTable($websiteTable); 
return $resource; 
} 
} 
48 / 54
UUsseerr PPrrooffiillee MMoodduullee CCoonnffiigg 
return array( 
[...] 
'service_manager' => array( 
'factories' => array( 
'UserV2RestUserProfileUserProfileResource' => 
'UserV2RestUserProfileUserProfileResourceFactory', 
'UserV2RestUserProfileTableUserTable' => 
'UserV2RestUserProfileTableUserTableFactory', 
'UserV2RestUserProfileTableWebsiteTable' => 
'UserV2RestUserProfileTableWebsiteTableFactory', 
), 
), 
); 
49 / 54
RREESSTT SSeerrvviiccee PPrrooffiill 
50 / 54
RREESSTT SSeerrvviiccee PPrrooffiillLLiissttee 
51 / 54
[A] 
EEPPIILLOOGG 
52 / 54
AAPPII ZZUUSSAAMMMMEENNKKLLIICCKKEENN 
Klappt für einfache APIs, ansonsten ist Handarbeit erforderlich... 
 
Repository: https://github.com/RalfEggert/phpughh-apigility 
53 / 54
BBiillddnnaacchhwweeiiss 
[A] Fotos von Ralf Eggert 
[1] Still here https://www.flickr.com/photos/thenovys/3784261365 von Abe Novy - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[2] Young student https://www.flickr.com/photos/audiolucistore/14159712431/ von www.audio-luci-store.it - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[3] Acorns https://www.flickr.com/photos/dno1967b/5431273344 von Daniel Oines - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[4] Fixing the database https://www.flickr.com/photos/dahlstroms/4140461901 von Håkan Dahlström - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[5] Monaco 14pt https://www.flickr.com/photos/polarity/3138680190 von Robert Agthe - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[6] RSA Securid Token - Credit Card Style https://www.flickr.com/photos/purpleslog/265657780 von Purple Slog - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[7] Shelf of Used Books https://www.flickr.com/photos/thedarkthing/5363586197 von William Ross - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[8] Ticket validator at Nice train station https://www.flickr.com/photos/traveleden/3797157077 von Simon - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[9] Test Lab - Supermicro Storage https://www.flickr.com/photos/jemimus/8533890844 von Robert - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[10] We are all fan of laptops https://www.flickr.com/photos/scottvanderchijs/4493248747 von Scott & Elaine van der Chijs - CC-BY https://creativecommons.org/licenses/by/2.0/ 
[11] Surprise https://www.flickr.com/photos/photographybycolby/11927931295 von Colby Stopa - CC-BY https://creativecommons.org/licenses/by/2.0/ 
Alle weiteren Screenshots wurden von Ralf Eggert erstellt. 
54 / 54

PHPunconf14: Apigility Einführung

  • 1.
    AAPPIIGGIILLIITTYY Heute klickenwir unsere API einfach mal zusammen...  1 / 54
  • 2.
    ÜÜbbeerr RRaallff EEggggeerrtt ● PHP seit 1999 ● Zend Framework 2 ● Trainer ● Berater ● Autor ● Insulaner 2 / 54
  • 3.
  • 4.
    [1] Neue API in 2 Stunden? 4 / 54
  • 5.
  • 6.
    [3] IInn aaNNuuttsshheellll 6 / 54
  • 7.
    RReessttffuull WWeebb SSeerrvviicceess CLIENT Web Browser PHP Javascript RUBY PYTHON REST SERVER /api/user/123 /api/user /api/user /api/user/123 /api/user/123 USER DOMAIN getUserEntity() getUserCollection() addUserEntity() updateUserEntity() deleteUserEntity() GET Request JSON Response GET Request JSON Response POST Request JSON Response PUT Request JSON Response DELETE Request JSON Response Integer UserEntity void UserCollection Array Boolean Integer, Array Boolean Integer Boolean 7 / 54
  • 8.
    RRPPCC WWeebb SSeerrvviicceess Local CLIENT javascript RPC Client JSON Method:getUser Params:id USER DOMAIN getUserEntity() GET Request JSON Result Integer UserEntity RPC Server /json-rpc.php Remote Call JSON Result javascript JSON Method:addUser Params:name addUserEntity() POST Request JSON Result Array Boolean /json-rpc.php Remote Call JSON Result javascript XML Method:getUser Params:id getUserEntity() GET Request XML Result Integer UserEntity /xml-rpc.php Remote Call XML Result javascript XML Method:addUser Params:name addUserEntity() POST Request XML Result Array Boolean /xml-rpc.php Remote Call XML Result 8 / 54
  • 9.
    VVeerrssiioonniieerruunngg ddeeffaauulltt VVeerrssiioonnppeerr UURRLL VVeerrssiioonn 11 ppeerr UURRLL VVeerrssiioonn 22 ppeerr UURRLL ddeeffaauulltt VVeerrssiioonn ppeerr CCoonntteenntt NNeeggoottiiaattiioonn VVeerrssiioonn 11 ppeerr CCoonntteenntt NNeeggoottiiaattiioonn VVeerrssiioonn 22 ppeerr CCoonntteenntt NNeeggoottiiaattiioonn 9 / 54
  • 10.
    JJSSOONN // HHAALL// PPrroobblleemm 10 / 54
  • 11.
    WWEEIITTEERREE FFEEAATTUURREESS [4,5, 6, 7, 8, 9] DDaatteennbbaannkk--bbaassiieerrtt CCooddee--bbaassiieerrtt aauutthheennttiiffiizziieerruunngg AAPPII DDookkuummeennttaattiioonn DDaatteennvvaalliiddiieerruunngg DDeeppllooyymmeenntt 11 / 54
  • 12.
    MMoodduullaarriissiieerruunngg ZZff--aappiiggiilliittyy ZZff--aappiiggiilliittyy--aaddmmiinnZZff--aappiiggiilliittyy--ddooccuummeennttaattiioonn ZZff--aappiiggiilliittyy--ddooccuummeennttaattiioonn--sswwaaggggeerr ZZff--aappiiggiilliittyy--pprroovviiddeerr ZZff--aappiiggiilliittyy--WWeellccoommee ZZff--aappii--pprroobblleemm ZZff--ccoonnffiigguurraattiioonn ZZff--ccoonntteenntt--nneeggoottiiaattiioonn ZZff--ccoonntteenntt--vvaalliiddaattiioonn ZZff--ddeeppllooyy ZZff--ddeevveellooppmmeenntt--mmooddee ZZff--hhaall ZZff--mmvvcc--aauutthh ZZff--ooaauutthh22 ZZff--rreesstt ZZff--RRPPCC ZZff--vveerrssiioonniinngg 12 / 54
  • 13.
    IInnssttaallllaattiioonn Composer direkt $ curl -s https://getcomposer.org/installer | php -- $ php composer.phar create-project -sdev zfcampus/zf-apigility-skeleton /path/to/install $ cd /path/to/install Git und Composer $ git clone https://github.com/zfcampus/zf-apigility-skeleton.git /path/to/install $ cd /path/to/install $ php composer.phar install ZIP und Composer $ wget https://github.com/zfcampus/zf-apigility-skeleton/archive/master.zip $ unzip -d /path/to/install master.zip $ cd /path/to/install $ php composer.phar install Entwicklungsmodus einschalten und Rechte setzen $ php public/index.php development enable $ sudo chmod 777 -R config/ $ sudo chmod 777 -R data/ $ sudo chmod 777 -R module/ 13 / 54
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
    [10] PPOOSSTT PPUUTT DDEELLEETTEE 23 / 54
  • 24.
    RReesstt SSeerrvviiccee PPoossttII Schritte 1 bis 3 24 / 54
  • 25.
    RReesstt SSeerrvviiccee PPoossttIIII Schritte 4 bis 6 25 / 54
  • 26.
    RReesstt SSeerrvviiccee PPuuttII Schritte 1 bis 3 26 / 54
  • 27.
    RReesstt SSeerrvviiccee PPuuttIIII Schritt 4 27 / 54
  • 28.
    RReesstt SSeerrvviiccee DDeelleettee Schritte 1 bis 3 28 / 54
  • 29.
  • 30.
    AAuutthheennttiiffiizziieerruunngg II HTTPBASIC HTTP DIGEST OAUTH2 HTpasswd $ htpasswd -c data/htpasswd apigility New password: ********* Re-type new password: ********* Adding password for user apigility $ 30 / 54
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
    [11] Was istdaran Code-basiert? 37 / 54
  • 38.
    GGeenneerriieerrttee DDaatteeiieenn Dateirechtesetzen und Dateien anzeigen $ cd /home/devhost/apigility.local/ $ sudo chmod 777 -R module/User/src/User/V2 $ ls -al module/User/src/User/V2/Rest/UserProfile/ drwxrwxrwx 2 www-data www-data 4096 Aug 30 21:39 . drwxrwxrwx 4 www-data www-data 4096 Aug 30 21:39 .. -rwxrwxrwx 1 www-data www-data 126 Aug 30 21:39 UserProfileCollection.php -rwxrwxrwx 1 www-data www-data 73 Aug 30 21:39 UserProfileEntity.php -rwxrwxrwx 1 www-data www-data 177 Aug 30 21:39 UserProfileResourceFactory.php -rwxrwxrwx 1 www-data www-data 2341 Aug 30 21:39 UserProfileResource.php Verzeichnis für table Gateway Klassen anlegen $ cd module/User/src/User/V2/Rest/UserProfile/ $ mkdir Table 38 / 54
  • 39.
    UUsseerr PPrrooffiillee eennttiittyy namespace UserV2RestUserProfile; class UserProfileEntity { protected $id; protected $name; protected $email; protected $contacts; protected $websites; public function setId($id) {} public function getId() {} public function setName($name) {} public function getName() {} public function setEmail($email) {} public function getEmail() {} public function setContacts(array $contacts) {} public function getContacts() {} public function setWebsites(array $websites) {} public function getWebsites() {} } 39 / 54
  • 40.
    UUsseerr TTaabbllee II namespace UserV2RestUserProfileTable; use ZendDbAdapterAdapterInterface; use ZendDbResultSetResultSetInterface; use ZendDbTableGatewayTableGateway; class UserTable extends TableGateway { public function __construct( AdapterInterface $adapter, ResultSetInterface $resultSetPrototype = null ) { $table = 'users'; parent::__construct($table, $adapter, null, $resultSetPrototype); } public function fetchUserById($id) { $select = $this->getSql()->select(); $select->where->equalTo('id', $id); return $this->selectWith($select)->current(); } [...] } 40 / 54
  • 41.
    UUsseerr TTaabbllee IIII namespace UserV2RestUserProfileTable; class UserTable extends TableGateway { [...] public function fetchContactsById($id) { $select = $this->getSql()->select(); $select->join('user_contacts', 'user_id_2 = id', array()); $select->where->equalTo('user_id_1', $id); return $this->selectWith($select)->toArray(); } public function fetchUsers($params) { $select = $this->getSql()->select(); return $this->selectWith($select)->toArray(); } } 41 / 54
  • 42.
    UUsseerr TTaabbllee ffaaccttoorryy namespace UserV2RestUserProfileTable; use ZendDbResultSetResultSet; use ZendServiceManagerFactoryInterface; use ZendServiceManagerServiceLocatorInterface; class UserTableFactory implements FactoryInterface { public function createService(ServiceLocatorInterface $serviceLocator) { $dbAdapter = $serviceLocator->get('MysqlAdapter'); $resultSet = new ResultSet(ResultSet::TYPE_ARRAY); $table = new UserTable($dbAdapter, $resultSet); return $table; } } 42 / 54
  • 43.
    WWeebbssiittee TTaabbllee namespaceUserV2RestUserProfileTable; use ZendDbAdapterAdapterInterface; use ZendDbResultSetResultSetInterface; use ZendDbTableGatewayTableGateway; class WebsiteTable extends TableGateway { public function __construct( AdapterInterface $adapter, ResultSetInterface $resultSetPrototype = null ) { $table = 'websites'; parent::__construct($table, $adapter, null, $resultSetPrototype); } public function fetchWebsitesById($id) { $select = $this->getSql()->select(); $select->join('user_websites', 'website_id = id', array()); $select->where->equalTo('user_id', $id); return $this->selectWith($select)->toArray(); } } 43 / 54
  • 44.
    WWeebbssiittee FFaaccttoorryy namespaceUserV2RestUserProfileTable; use ZendDbResultSetResultSet; use ZendServiceManagerFactoryInterface; use ZendServiceManagerServiceLocatorInterface; class WebsiteTableFactory implements FactoryInterface { public function createService(ServiceLocatorInterface $serviceLocator) { $dbAdapter = $serviceLocator->get('MysqlAdapter'); $resultSet = new ResultSet(ResultSet::TYPE_ARRAY); $table = new WebsiteTable($dbAdapter, $resultSet); return $table; } } 44 / 54
  • 45.
    UUsseerr PPrrooffiillee RReessoouurrcceeII namespace UserV2RestUserProfile; use UserV2RestUserProfileTableUserTable; use UserV2RestUserProfileTableWebsiteTable; use ZFApiProblemApiProblem; use ZFRestAbstractResourceListener; class UserProfileResource extends AbstractResourceListener { protected $userTable; protected $websiteTable; public function setUserTable($userTable) {} public function getUserTable() {} public function setWebsiteTable($websiteTable) {} public function getWebsiteTable() {} protected function addContactsAndWebsites(array $user) { $user['contacts'] = $this->getUserTable()->fetchContactsById($user['id']); $user['websites'] = $this->getWebsiteTable()->fetchWebsitesById($user['id']); return $user; } [...] } 45 / 54
  • 46.
    UUsseerr PPrrooffiillee RReessoouurrcceeIIII namespace UserV2RestUserProfile; class UserProfileResource extends AbstractResourceListener { [...] public function create($data) { return new ApiProblem(405, 'The POST method has not been defined'); } public function delete($id) {} public function deleteList($data) {} public function fetch($id) { $user = $this->getUserTable()->fetchUserById($id); if (!$user) { return new ApiProblem(404, 'User profile for id ' . $id . ' not found'); } return $this->addContactsAndWebsites($user); } [...] } 46 / 54
  • 47.
    UUsseerr PPrrooffiillee RReessoouurrcceeIIIIII namespace UserV2RestUserProfile; class UserProfileResource extends AbstractResourceListener { [...] public function fetchAll($params = array()) { $users = $this->getUserTable()->fetchUsers($params); if (!$users) { return new ApiProblem(404, 'No user profiles found'); } foreach ($users as $key => $user) { $users[$key] = $this->addContactsAndWebsites($user); } return $users; } public function patch($id, $data) {} public function replaceList($data) {} public function update($id, $data) {} } 47 / 54
  • 48.
    UUsseerr PPrrooffiillee RReessoouurrcceeFFaaccttoorryy namespace UserV2RestUserProfile; class UserProfileResourceFactory { public function __invoke($services) { $userTable = $services->get( 'UserV2RestUserProfileTableUserTable' ); $websiteTable = $services->get( 'UserV2RestUserProfileTableWebsiteTable' ); $resource = new UserProfileResource(); $resource->setUserTable($userTable); $resource->setWebsiteTable($websiteTable); return $resource; } } 48 / 54
  • 49.
    UUsseerr PPrrooffiillee MMoodduulleeCCoonnffiigg return array( [...] 'service_manager' => array( 'factories' => array( 'UserV2RestUserProfileUserProfileResource' => 'UserV2RestUserProfileUserProfileResourceFactory', 'UserV2RestUserProfileTableUserTable' => 'UserV2RestUserProfileTableUserTableFactory', 'UserV2RestUserProfileTableWebsiteTable' => 'UserV2RestUserProfileTableWebsiteTableFactory', ), ), ); 49 / 54
  • 50.
  • 51.
  • 52.
  • 53.
    AAPPII ZZUUSSAAMMMMEENNKKLLIICCKKEENN Klapptfür einfache APIs, ansonsten ist Handarbeit erforderlich...  Repository: https://github.com/RalfEggert/phpughh-apigility 53 / 54
  • 54.
    BBiillddnnaacchhwweeiiss [A] Fotosvon Ralf Eggert [1] Still here https://www.flickr.com/photos/thenovys/3784261365 von Abe Novy - CC-BY https://creativecommons.org/licenses/by/2.0/ [2] Young student https://www.flickr.com/photos/audiolucistore/14159712431/ von www.audio-luci-store.it - CC-BY https://creativecommons.org/licenses/by/2.0/ [3] Acorns https://www.flickr.com/photos/dno1967b/5431273344 von Daniel Oines - CC-BY https://creativecommons.org/licenses/by/2.0/ [4] Fixing the database https://www.flickr.com/photos/dahlstroms/4140461901 von Håkan Dahlström - CC-BY https://creativecommons.org/licenses/by/2.0/ [5] Monaco 14pt https://www.flickr.com/photos/polarity/3138680190 von Robert Agthe - CC-BY https://creativecommons.org/licenses/by/2.0/ [6] RSA Securid Token - Credit Card Style https://www.flickr.com/photos/purpleslog/265657780 von Purple Slog - CC-BY https://creativecommons.org/licenses/by/2.0/ [7] Shelf of Used Books https://www.flickr.com/photos/thedarkthing/5363586197 von William Ross - CC-BY https://creativecommons.org/licenses/by/2.0/ [8] Ticket validator at Nice train station https://www.flickr.com/photos/traveleden/3797157077 von Simon - CC-BY https://creativecommons.org/licenses/by/2.0/ [9] Test Lab - Supermicro Storage https://www.flickr.com/photos/jemimus/8533890844 von Robert - CC-BY https://creativecommons.org/licenses/by/2.0/ [10] We are all fan of laptops https://www.flickr.com/photos/scottvanderchijs/4493248747 von Scott & Elaine van der Chijs - CC-BY https://creativecommons.org/licenses/by/2.0/ [11] Surprise https://www.flickr.com/photos/photographybycolby/11927931295 von Colby Stopa - CC-BY https://creativecommons.org/licenses/by/2.0/ Alle weiteren Screenshots wurden von Ralf Eggert erstellt. 54 / 54