ที่เก็บนี้มีกรอบเล็กน้อยที่สามารถทำ restapi ได้อย่างง่ายดายด้วย PHP
PDOUtilsRepository เก็บเพื่อใช้ PDOUtilsApiException.phpRest::handleRequest เพื่อส่งคืน http 409 เมื่อมีการยกข้อยกเว้นRest::existFile FASTIVESingletonController->getAllRest::scalePicturedbIgnoreController->getByFieldsRest::uploadFile FUNCTIONRest::$uploadDirRest::getUploadDir()Rest::configureUploadDir()Rest::createDirectoryRecursive()GuardsRoleKeyValue และ KeyValueList โครงสร้างโครงสร้างService และคลาส RepositoryCredentialsdeleteByField()getByField() มันจะส่งคืน Model[] แทน Model ในการเริ่มต้นคุณจะต้องสร้างโฟลเดอร์ (ฉันตั้งชื่อมัน /rest ) และวางโฟลเดอร์ ApiRest ไว้ข้างใน ไฟล์หลักจะเป็น api.php : มันจะสร้าง restapi เชื่อมต่อกับ DB และฟังคำขอ
นี่คือเนื้อหาเริ่มต้นในไฟล์นี้:
<?php
require_once __DIR__ . " /ApiRest/RestAPI.php " ;
header ( ' Content-Type: application/json ' );
header ( ' Access-Control-Allow-Headers: Content-Type, enctype, token ' );
header ( ' Access-Control-Allow-Origin: * ' );
header ( ' Access-Control-Allow-Methods: GET, POST, PUT, DELETE ' );
$ restAPI = new RestAPI ( " localhost " , " myDB " , " root " , "" );
// You can add an argument to improve the security of your session like this :
//$restAPI = new RestAPI("localhost", "myDB", "root", "", "m*;rO)P7^)3'k[F'S~h0Lx7{zN%`6S");
Rest:: configureUploadDir ( " rest-upload " );
echo $ restAPI -> handleRequest (); ตอนนี้ Restapi พร้อมใช้งาน คุณสามารถตรวจสอบได้ด้วยบุรุษไปรษณีย์และกด URL ด้วยวิธี GET : http://your-domain/your-path/rest/api.php/user
มันเจ๋ง แต่ Restapi จัดการได้อย่างไร?
api.php (นี่คือ user คำ)user หรือไม่user/include.php หรือไม่UserControllerprocessUrl ในไดเรกทอรี user คุณจะพบตัวอย่างในการเพิ่มพา ธ ไปยังส่วนที่เหลือ API ของคุณสำหรับวัตถุ User แต่ละไฟล์ที่เกี่ยวข้องกับวัตถุ / คลาส / ตารางเฉพาะจะต้องอยู่ในโฟลเดอร์เดียวกันและปฏิบัติตามกฎเดียวกันกับผู้ใช้:
/modelname/include.phpModelName.controller.phpModelName.model.phpModelName.repository.phpModelName.service.php คอนโทรลเลอร์เป็นชั้นแรกที่เรียกโดย restapi พวกเขาจะต้องมีชื่อเช่นนี้: modelClassName + "Controller" โดยค่าเริ่มต้นเส้นทางเหล่านี้จะถูกสร้างขึ้นโดยค่าเริ่มต้น:
api.php/modelClassNameapi.php/modelClassName/$idapi.php/modelClassNameapi.php/modelClassNameapi.php/modelClassName/$idโดยค่าเริ่มต้นแต่ละเส้นทางที่สร้างขึ้นจะเชื่อมโยงกับ Guard Loginguard หากคุณต้องการลบยามคุณจะต้องแทนที่ ApiRoute โดยประกาศในคอนโทรลเลอร์ของคุณ
คุณสามารถเพิ่มตัวกรองในฟังก์ชั่น GetAll โดยการเพิ่มค่ารับบน URL ตัวอย่าง :
api.php/modelClassName?lastname=Doe
นี่คือตัวอย่างของคลาส usercontroller:
<?php
// FILE rest/user/User.controller.php
require_once __DIR__ . " /../ApiRest/Rest.php " ;
require_once __DIR__ . " /../ApiRest/Controller.php " ;
class UserController extends Controller {
public function __construct ( string $ modelName ) {
parent :: __construct ( $ modelName );
$ this -> createApiRoute (Rest:: PUT , ' login ' , " login " );
$ this -> createApiRoute (Rest:: POST , ' picture ' , " uploadPicture " , [ new LoginGuard ()]);
}
/* PUT */
public static function login ( array $ params , stdClass $ body ): string {
$ user = User:: fromJSON ( $ body );
return static :: $ service -> login ( $ user );
}
public static function uploadPicture (): string {
$ fileName = " htmlInputName " ;
$ newName = " profilePicture.png " ;
Rest:: uploadFile ( $ fileName , $ newName );
return "" ;
}
} เมื่อคุณเรียกฟังก์ชั่น createApiRoute() พารามิเตอร์ที่สองจะสอดคล้องกับเส้นทางของคำขอ ในสตริงนี้คุณสามารถเพิ่มพารามิเตอร์แบบไดนามิกได้เช่น 'customPath/$param1/$param2/anything' จากนั้นเมื่อเรียกใช้ฟังก์ชันที่เกี่ยวข้องคุณจะพบค่าของ $param1 และ $param2 บนตัวแปร $params :
var_dump ( $ params );
// print :
// array(
// "param1" => "value1",
// "param2" => "value2",
//)คุณสามารถแทนที่เส้นทางด้วยเส้นทางอื่นโดยไม่ต้องลบออกหากพวกเขาไม่มีพารามิเตอร์จำนวนเท่ากัน ตัวอย่างเช่นเส้นทางเหล่านี้จะถูกเก็บไว้:
$ this -> createApiRoute (Rest:: GET , ' $id ' , " getById " );
$ this -> createApiRoute (Rest:: GET , ' current ' , " getCurrent " );ถ้าเป็นไปได้เส้นทาง 'ปัจจุบัน' จะถูกเรียกใช้ หากไม่เป็นเช่นนั้นเส้นทาง '$ id' จะถูกเรียกใช้
บริการเป็นเลเยอร์ถัดไปที่เรียกโดยคอนโทรลเลอร์: อยู่ระหว่างคลาสคอนโทรลเลอร์และคลาสที่เก็บ บริการถูกใช้เพื่อรับข้อมูลจากคลาส Repository และทำให้กระบวนการเป็นข้อมูล
คลาส Service ยังสามารถโทรหาบริการอื่น ๆ เพื่อข้ามข้อมูลและทำกระบวนการพิเศษ
โดยค่าเริ่มต้นฟังก์ชั่นที่เกี่ยวข้องกับเส้นทางของคอนโทรลเลอร์ถูกสร้างขึ้น:
getAll()getByID(string $id)create()update()delete(string $id)นี่คือตัวอย่างของคลาส Userservice:
<?php
// FILE rest/user/User.service.php
require_once __DIR__ . " /../ApiRest/Service.php " ;
class UserService extends Service {
public function login ( User $ user ): string {
return $ this -> repository -> login ( $ user );
}
function initialize () { }
} หากคุณต้องการใช้ Service อื่นในชั้นเรียนเหล่านี้คุณต้องประกาศและเริ่มต้นคลาส Service ในฟังก์ชัน initialize เช่นนี้:
<?php
class UserService extends Service {
/** @var $bookService BookService */
public $ bookService ;
public function login ( User $ user ): string {
return $ this -> repository -> login ( $ user );
}
function initialize () {
$ this -> bookService = BookService:: getInstance ( " Book " );
}
}ที่เก็บเป็นชั้นสุดท้ายที่เรียกโดยบริการ พวกเขามีการสืบค้น SQL และรับวัตถุโมเดลจากฐานข้อมูล
เช่นเดียวกับบริการโดยเริ่มต้นฟังก์ชั่นเหล่านี้:
getAll()getByID(string $id)create()update()delete(string $id)นี่คือตัวอย่างของคลาส UserRepository:
<?php
// FILE rest/user/User.repository.php
require_once __DIR__ . " /../ApiRest/Repository.php " ;
class UserRepository extends Repository {
public function __construct () {
parent :: __construct ( " user " , ' User ' );
}
public function login ( User $ user ): string {
$ fields = new KeyValueList ([
new KeyValue ( " name " , $ user -> name ),
new KeyValue ( " password " , $ user -> password )
]);
$ matchedUsers = $ this -> getByFields ( $ fields );
if ( count ( $ matchedUsers ) != 1 )
throw new Exception ( " UserRepository->login() : $ matchedUsers have a size of " . count ( $ matchedUsers ) . " instead of 1 ! " );
$ loggedUser = $ matchedUsers [ 0 ];
if ( $ loggedUser )
return Rest:: IDToToken ( $ loggedUser -> id );
else
return "" ;
}
}หากคุณต้องการใช้การสืบค้น SQL แบบกำหนดเองคุณสามารถใช้คลาส Pdoutils เพื่อดำเนินการได้ นี่คือตัวอย่าง:
$ query = " < CUSTOM_SELECT_QUERY > " ;
$ PDOStatement = PDOUtils:: executeQuery ( $ query );
return static :: getByPDOStatement ( $ PDOStatement ); มีฟังก์ชั่นบางอย่างที่คุณสามารถใช้ได้จาก PDOUtils :
executeQuery(query)executeQueryWithParameter(query, keyValue)executeQueryWithParameters(query, KeyValueList)โมเดลเป็นคลาสที่แสดงถึงบรรทัดในฐานข้อมูล
เมื่อข้อมูลถูกดึงมาจากฐานข้อมูลบูลีนจะไม่เท่ากับ true / false แต่เป็น '1' / '0' ในการกลับไปที่บูลีนที่ถูกขโมยของเราคุณสามารถเรียกฟังก์ชัน preserveBooleans() เพื่อแปลงฟิลด์บูลีน
หากต้องการทำเครื่องหมายฟิลด์เหมือนฟิลด์บูลีนเพียงเรียกใช้ฟังก์ชั่นนี้ภายในคอนสตรัคเตอร์: addBoolean("booleanField1", "booleanField2", ...)
ในทำนองเดียวกันคุณสามารถทำเครื่องหมายฟิลด์เป็น jsonignore ได้โดยเรียกฟังก์ชั่น addIgnore("ignoredField1", ...) จากนั้นเพื่อแปลงอินสแตนซ์ของโมเดลเป็นฟังก์ชัน JSON เรียกใช้ฟังก์ชัน encode() !
มีฟังก์ชั่นอื่น: addDbIgnore("field1", ...) ใช้เพื่อระบุว่าฟิลด์ใดที่ไม่ได้เก็บไว้ในฐานข้อมูล
คลาสโมเดลสามารถเรียกคืนได้จาก JSON โดยใช้ฟังก์ชั่นคงที่นี้: Model::fromJSON(stdClass $data)
ยามถูกใช้เพื่อ จำกัด การเข้าถึงข้อมูลขึ้นอยู่กับบทบาทของผู้ใช้ สามยามถูกสร้างขึ้นโดยค่าเริ่มต้น:
AdminGuardModeratorGuardLoginGuard พวกเขาทั้งหมดขยายคลาสนามธรรม Guard และใช้ authorizeAccess(): bool คุณสามารถสร้างตัวป้องกันของคุณเองได้ตามกฎเดียวกันจากนั้นเพิ่มบรรทัดใหม่ในไฟล์ include.php ในไดเรกทอรี Guard
ผู้คุมจะถูกเรียกในชั้นเรียนคอนโทรลเลอร์เมื่อคุณจะประกาศเส้นทาง โปรดทราบว่าเส้นทางสามารถมี 0, 1 หรือหลายยาม
สามารถยกข้อยกเว้นได้เมื่อมีปัญหาที่จะพิมพ์ในเว็บไซต์ส่วนหน้า ในการทำเช่นนั้นคุณต้องโยน ApiException และเซิร์ฟเวอร์จะตอบกลับด้วยข้อผิดพลาด HTTP 409
คลาส ApiException ขยายคลาส Exception แต่ไม่ได้ใช้พารามิเตอร์จาก superclass
คลาสนี้ทำขึ้นเพื่อใช้เครื่องมือ Frondend สากลบางอย่างได้อย่างง่ายดาย: มันมีพารามิเตอร์ key ซึ่งสามารถเป็นกุญแจสำคัญของการแปลในไฟล์ JSON และพารามิเตอร์ parameters ที่มีข้อมูลที่จะส่ง ตัวอย่างเช่นนี่คือ Apiexception และไฟล์ JSON Internationalization ที่เกี่ยวข้อง:
throw new ApiException ( " api-error.error1 " , [ " name " => ' John ' ]);{
"api-error" : {
"error1" : {
"title" : " Hey ! " ,
"text" : " Hello {{name}} "
}
}
} เมื่อใช้ Apiexception ข้อมูลเหล่านี้จะถูกเก็บไว้ในคุณสมบัติ error ของรายการ JavaScript HttpErrorResponse
เพิ่มความสามารถในการบังคับประเภทของฟิลด์ของแต่ละรุ่นเป็นอย่างอื่นไม่มีการปรับปรุงในอนาคตที่วางแผนไว้ในขณะนี้ ไม่ได้หมายความว่าแพ็คเกจจะไม่ได้รับการอัปเดต!