Dieses Repository enthält ein kleines Framework, das mit PHP leicht wieder restAPI durchführen kann
PDOUtils Klasse hinzugefügtRepository -Klasse, um PDOUtils zu verwendenApiException.php Klasse hinzugefügtRest::handleRequest , um ein HTTP 409 zurückzugeben, wenn eine Ausnahme erhöht wirdRest::existFile die DateifunktionSingleton -DesignmusterController->getAll -FunktionRest::scalePicture -FunktiondbIgnore -Funktion hinzugefügtController->getByFields -Funktionen hinzugefügtRest::uploadFile -Funktion hinzugefügtRest::$uploadDirRest::getUploadDir()Rest::configureUploadDir()Rest::createDirectoryRecursive()Guards hinzugefügtRole hinzugefügtKeyValue und KeyValueList -Strukturklasse hinzugefügtService und Repository -KlassenCredentials Class hinzugefügtdeleteByField() Funktion hinzugefügtgetByField() -Funktion, sie kehrt jetzt Model[] anstelle von Model zurück Zu Beginn müssen Sie einen Ordner (ich habe ihn /rest benannt) erstellen und den ApiRest Ordner in den Ordner platzieren. Die Hauptdatei ist api.php : Sie erstellt den RestAPI, eine Verbindung zum DB und hört auf Anfragen an.
Hier ist der Standardinhalt in dieser Datei:
<?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 (); Jetzt ist der Restapi bereit zu verwenden. Sie können es mit Postman überprüfen und die URL mit der GET -Methode treffen: http://your-domain/your-path/rest/api.php/user .
Es ist cool, aber wie umgeht der Restapi damit?
api.php (hier ist es der Wort user )user existiertuser/include.php -Datei vorhanden istUserControllerprocessUrl Im user finden Sie ein Beispiel, um Ihre API -Ruhe für ein User Pfade hinzuzufügen. Alle Dateien, die sich auf ein bestimmtes Objekt / eine bestimmte Klasse / eine bestimmte Tabelle beziehen, muss sich im selben Ordner befinden und dieselben Regeln wie Benutzer befolgen:
/modelname/include.phpModelName.controller.phpModelName.model.phpModelName.repository.phpModelName.service.php Controller sind die erste Schicht, die von den Restapi genannt wird. Sie müssen so genannt werden: modelClassName + "Controller" . Standardmäßig werden diese Pfade standardmäßig generiert:
api.php/modelClassNameapi.php/modelClassName/$idapi.php/modelClassNameapi.php/modelClassNameapi.php/modelClassName/$idStandardmäßig ist jeder erzeugte Pfad dem Wach -Liegeuard zugeordnet. Wenn Sie die Wache entfernen möchten, müssen Sie die Apiroute überschreiben, indem Sie ihn in Ihrem Controller deklarieren.
Sie können einen Filter in die GetAll -Funktion hinzufügen, indem Sie GET -Werte auf der URL hinzufügen. Beispiel :
api.php/modelClassName?lastname=Doe
Hier ist ein Beispiel für eine UserController -Klasse:
<?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 "" ;
}
} Wenn Sie die Funktion createApiRoute() aufrufen, entspricht der zweite Parameter dem Pfad der Anforderung. In dieser Zeichenfolge können Sie dynamische Parameter wie diesen 'customPath/$param1/$param2/anything' hinzufügen. Wenn die zugehörige Funktion aufgerufen wird, finden Sie Werte von $param1 und $param2 für die $params -Variable:
var_dump ( $ params );
// print :
// array(
// "param1" => "value1",
// "param2" => "value2",
//)Sie können eine Route mit einem anderen überschreiben, ohne sie zu entfernen, wenn sie nicht die gleiche Menge an Parametern haben. Zum Beispiel werden diese Routen aufbewahrt:
$ this -> createApiRoute (Rest:: GET , ' $id ' , " getById " );
$ this -> createApiRoute (Rest:: GET , ' current ' , " getCurrent " );Wenn möglich, wird die Route "Strom" ausgelöst. Wenn dies nicht der Fall ist, wird die Route "$ id" ausgelöst.
Dienste sind die nächste Schicht, die von Controllern bezeichnet wird: Sie befinden sich zwischen Controller -Klassen und Repository -Klassen. Dienste werden verwendet, um Daten aus Repository -Klassen abzurufen und die Daten zu verarbeiten.
Service können auch andere Dienste anrufen, um Daten zu überschreiten und einen besonderen Prozess durchzuführen.
Standardmäßig werden Funktionen generiert, die den Pfaden des Controller zugeordnet sind:
getAll()getByID(string $id)create()update()delete(string $id)Hier ist ein Beispiel für eine UserService -Klasse:
<?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 () { }
} Wenn Sie einen anderen Service in der Klasse der dieser Klasse nutzen möchten, müssen Sie ihn deklarieren und die Service in der initialize Funktion wie folgt initialisieren:
<?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 " );
}
}Repositorys sind die endgültige Schicht, die von Diensten bezeichnet wird. Sie enthalten SQL -Abfragen und erhalten Modelle Objekt aus der Datenbank.
Wie bei Diensten sind die Funktionen standardmäßig verfügbar:
getAll()getByID(string $id)create()update()delete(string $id)Hier ist ein Beispiel für die USERRepository -Klasse:
<?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 "" ;
}
}Wenn Sie benutzerdefinierte SQL -Abfragen verwenden möchten, können Sie die PDoutils -Klasse verwenden, um sie auszuführen. Hier ist ein Beispiel:
$ query = " < CUSTOM_SELECT_QUERY > " ;
$ PDOStatement = PDOUtils:: executeQuery ( $ query );
return static :: getByPDOStatement ( $ PDOStatement ); Es gibt einige Funktionen, die Sie von PDOUtils verwenden können:
executeQuery(query)executeQueryWithParameter(query, keyValue)executeQueryWithParameters(query, KeyValueList)Modelle sind die Klassen, die eine Zeile in der Datenbank darstellen.
Wenn Daten aus der Datenbank abgerufen werden, sind Booleane nicht gleich / true false sondern '1' / '0' . Um unsere gestohlenen Booleschen zurückzubekommen, können Sie die Funktion preserveBooleans() nennen, um die Booleschen Felder zu konvertieren.
Um ein Feld wie ein boolescher Feld zu markieren, nennen Sie diese Funktion einfach im Konstruktor: addBoolean("booleanField1", "booleanField2", ...)
Auf die gleiche Weise können Sie ein Feld als JSONIGNORE markieren, indem Sie den Funktion addIgnore("ignoredField1", ...) . Um die Instanzen des Modells in JSON in JSON zu konvertieren, rufen Sie die Funktion encode() auf!
Es gibt eine andere Funktion: addDbIgnore("field1", ...) mit der angegeben wird, welche Felder nicht in der Datenbank gespeichert sind.
Modellklassen können mit dieser statischen Funktion aus JSON abgerufen werden: Model::fromJSON(stdClass $data) .
Wachen werden verwendet, um den Datenzugriff abhängig von der Rolle des Benutzers einzuschränken. Standardmäßig werden drei Wachen erstellt:
AdminGuardModeratorGuardLoginGuard Sie alle erweitern die abstrakte Guard und implementieren die authorizeAccess(): bool -Funktion. Sie können auch Ihre eigene Wache erstellen, die dieselben Regeln folgen, und dann eine neue Zeile in der Datei include.php im Guard -Verzeichnis hinzufügen.
Wachen werden in den Controllers -Klassen aufgerufen, wenn Sie die Route deklarieren. Beachten Sie, dass eine Route 0, 1 oder mehrere Wachen haben kann.
Eine Ausnahme kann angelegt werden, wenn auf der Front-End-Website ein Problem aufgedruckt wird. Dazu müssen Sie eine ApiException werfen und der Server wird mit einem HTTP 409 -Fehler antworten.
Die ApiException -Klasse erweitert die Exception , verwendet jedoch keine Parameter aus der Superklasse.
Diese Klasse wird so erstellt, dass sie einfach ein Internationalisierungs -Wedend -Tool verwenden: Sie enthält einen key , der der Schlüssel der Übersetzung in der JSON -Datei sein kann, und einen parameters , der die zu übertragenden Daten enthalten. Zum Beispiel finden Sie hier eine Apiexception und die zugehörige JSON -Internationalisierungsdatei:
throw new ApiException ( " api-error.error1 " , [ " name " => ' John ' ]);{
"api-error" : {
"error1" : {
"title" : " Hey ! " ,
"text" : " Hello {{name}} "
}
}
} Bei Verwendung einer Apiexception werden diese Daten in der error des HttpErrorResponse JavaScript -Elements gespeichert.
Fügen Sie die Fähigkeit hinzu, den Typ des Feldes jedes Modells zu erzwingen, sonst sind jetzt keine zukünftigen Verbesserungen geplant. Bedeutet nicht, dass das Paket nicht aktualisiert wird!