Este repositorio contiene un pequeño marco capaz de hacer un reestapi fácilmente con PHP
PDOUtils agregadaRepository limpia para usar PDOUtilsApiException.php claseRest::handleRequest para devolver un HTTP 409 cuando se plantea la excepciónRest::existFileSingletonController->getAllRest::scalePicturedbIgnore agregadaController->getByFieldsRest::uploadFile agregadoRest::$uploadDirRest::getUploadDir()Rest::configureUploadDir()Rest::createDirectoryRecursive()Guards agregadosRole adicionalKeyValue y Clase de Estructura KeyValueListService actualizado y clases RepositoryCredentials agregadasdeleteByField()getByField() actualizado, devuelve ahora Model[] en lugar del Model Para comenzar, tendrá que crear una carpeta (la llamé /rest ) y colocar la carpeta ApiRest adentro. El archivo principal será api.php : creará el RaTapi, se conectará a la DB y escuchará las solicitudes.
Aquí está el contenido predeterminado en este archivo:
<?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 (); Ahora el reestapi está listo para usar. Puede verificarlo con Postman y presionar la URL con el método GET : http://your-domain/your-path/rest/api.php/user .
Es genial, pero ¿cómo el reestapi maneja eso?
api.php (aquí está la palabra user )useruser/include.phpUserControllerprocessUrl En el directorio user , encontrará un ejemplo para agregar rutas a su REST API para un objeto User . Cada archivos relacionados con un objeto / clase / tabla específico deberá estar en la misma carpeta y seguir las mismas reglas que el usuario:
/modelname/include.phpModelName.controller.phpModelName.model.phpModelName.repository.phpModelName.service.php Los controladores son la primera capa llamada por el reestapi. Tienen que ser nombrados así: modelClassName + "Controller" . De forma predeterminada, las rutas de TESE se generan de forma predeterminada:
api.php/modelClassNameapi.php/modelClassName/$idapi.php/modelClassNameapi.php/modelClassNameapi.php/modelClassName/$idPor defecto, cada ruta generada está asociada a la Guard Loginguard. Si desea eliminar el guardia, tendrá que anular el apuro declarándolo en su controlador.
Puede agregar un filtro en la función Getall agregando valores GET en la URL. Ejemplo :
api.php/modelClassName?lastname=Doe
Aquí hay un ejemplo de una clase de 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 "" ;
}
} Cuando llama a la función createApiRoute() , el segundo parámetro corresponde a la ruta de la solicitud. En esta cadena, puede agregar parámetros dinámicos como este 'customPath/$param1/$param2/anything' . Luego, cuando se llame a la función asociada, encontrará valores de $param1 y $param2 en la variable $params :
var_dump ( $ params );
// print :
// array(
// "param1" => "value1",
// "param2" => "value2",
//)Puede anular una ruta con otra sin eliminarla, si no tienen la misma cantidad de parámetros. Por ejemplo, estas rutas se mantendrán:
$ this -> createApiRoute (Rest:: GET , ' $id ' , " getById " );
$ this -> createApiRoute (Rest:: GET , ' current ' , " getCurrent " );Si es posible, se activará la ruta 'actual'. Si no es así, se activará la ruta '$ id'.
Los servicios son la siguiente capa llamada por controladores: están entre clases de controlador y clases de repositorio. Los servicios se utilizan para obtener datos de las clases Repository y hacer del proceso los datos.
Las clases Service también pueden llamar a otros servicios para cruzar datos y hacer un proceso especial.
Por defecto, se generan funciones asociadas a las rutas del controlador:
getAll()getByID(string $id)create()update()delete(string $id)Aquí hay un ejemplo de una clase de servicio de usuarios:
<?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 () { }
} Si desea utilizar otro Service en la clase TESES, debe declararlo e inicializar la clase Service en la función initialize como esta:
<?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 " );
}
}Los repositorios son la capa final llamada por los servicios. Contienen consultas SQL y obtienen objeto de modelos de la base de datos.
Igual que los servicios, por defecto, estas funciones están disponibles:
getAll()getByID(string $id)create()update()delete(string $id)Aquí hay un ejemplo de clase de 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 "" ;
}
}Si desea usar consultas SQL personalizadas, puede usar la clase PDOUTILS para ejecutarlas. Aquí hay un ejemplo:
$ query = " < CUSTOM_SELECT_QUERY > " ;
$ PDOStatement = PDOUtils:: executeQuery ( $ query );
return static :: getByPDOStatement ( $ PDOStatement ); Hay algunas funciones que puede usar de PDOUtils :
executeQuery(query)executeQueryWithParameter(query, keyValue)executeQueryWithParameters(query, KeyValueList)Los modelos son las clases que representan una línea en la base de datos.
Cuando los datos se recuperan de la base de datos, los booleanos no serán iguales a true / false sino a '1' / '0' . Para recuperar nuestros booleanos robados, puede llamar a la función preserveBooleans() para convertir los campos booleanos.
Para marcar un campo como un campo booleano, simplemente llame a esta función dentro del constructor: addBoolean("booleanField1", "booleanField2", ...)
De la misma manera, puede marcar un campo como Jsonignore llamando a la función addIgnore("ignoredField1", ...) . ¡Luego, para convertir las instancias del modelo a JSON llame a la función encode() !
Hay otra función: addDbIgnore("field1", ...) utilizada para especificar qué campos no se almacenan en la base de datos.
Las clases de modelo se pueden recuperar de JSON utilizando esta función estática: Model::fromJSON(stdClass $data) .
Los guardias se utilizan para restringir el acceso a los datos según el rol del usuario. Se crean tres guardias de forma predeterminada:
AdminGuardModeratorGuardLoginGuard Todos extienden la clase abstracta Guard e implementan la función authorizeAccess(): bool . También puede crear su propia guardia siguiendo las mismas reglas y luego agregar una nueva línea en el archivo include.php en el directorio de Guard .
Se llaman a los guardias en las clases de controladores, cuando declare la ruta. Tenga en cuenta que una ruta puede tener 0, 1 o múltiples guardias.
Se puede plantear la excepción cuando se debe imprimir un problema que se exhibirá en el sitio web front-end. Para hacerlo, debe lanzar una ApiException y el servidor responderá con un error HTTP 409 .
La clase ApiException extiende la clase Exception , pero no usa parámetros de la superclase.
Esta clase se realiza de manera que use fácilmente alguna herramienta de internacionalización frondend: contiene un parámetro key que puede ser la clave de la traducción en el archivo JSON, y un parámetro parameters que contiene los datos a transmitir. Por ejemplo, aquí hay una Apiexception y el archivo de internacionalización JSON asociado:
throw new ApiException ( " api-error.error1 " , [ " name " => ' John ' ]);{
"api-error" : {
"error1" : {
"title" : " Hey ! " ,
"text" : " Hello {{name}} "
}
}
} Al usar una Apiexception, estos datos se almacenarán en la propiedad error del elemento JavaScript HttpErrorResponse .
Agregue la capacidad de forzar el tipo de campo de cada modelo, de lo contrario, no hay mejoras futuras planificadas ahora. ¡No significa que el paquete no se actualice!