Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/andy87/knock-knock
Facade for PHP requests on cURL
https://github.com/andy87/knock-knock
api api-client api-gateway api-wrapper curl curl-library curlphp httpclient php php-library php8
Last synced: 21 days ago
JSON representation
Facade for PHP requests on cURL
- Host: GitHub
- URL: https://github.com/andy87/knock-knock
- Owner: andy87
- Created: 2024-05-15T16:45:53.000Z (6 months ago)
- Default Branch: master
- Last Pushed: 2024-06-28T06:29:16.000Z (4 months ago)
- Last Synced: 2024-06-28T07:34:07.845Z (4 months ago)
- Topics: api, api-client, api-gateway, api-wrapper, curl, curl-library, curlphp, httpclient, php, php-library, php8
- Language: PHP
- Homepage:
- Size: 1.13 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
KnockKnock
KnockKnock - это простая библиотека, реализующая Фасад и предоставляющая удобный интерфейс для выполнения запросов в PHP,
используя расширение cURL. Она упрощает работу, предоставляя более высокоуровневый API и быстрый доступ к настройкам.Цель: сделать простой и лёгкий в настройке компонента и запроса пакет.
P.S. я знаю про существование таких библиотек как: [Guzzle](https://github.com/guzzle/guzzle), [Client](https://github.com/yiisoft/yii2-httpclient) _(в моём любимом Yii2)_, но хотелось попробовать создать свою реализацию.
Без "лишних" данных, вызовов и настроек, nullWarningStyle - только то, что нужно: сухо, лаконично, минималистично.
_Разумеется, это не конкурент, а просто попытка создать что-то своё_### Содержание:
- [Установка](#knockknock-setup)
- [Объект - Базовый класс](#knockknock-src-Operator)
- [Объект - Запрос](#knockknock-src-Request)
- [Объект - Ответ](#knockknock-src-Response)
- [Дополнительные возможности](#knockknock-src-feature)
- [Расширение на основе базового класса](#knockknock-extends)
- [Пример Custom реализации](#knockknock-Custom)
- [Тесты](#knockknock-tests)___
УстановкаТребования
- php 8.0
- ext cURL
- ext JSON
Composer## Добавление пакета в проект
Используя: консольные команды. (Предпочтительней)
- при composer, установленном локально:
```bash
composer require andy87/knockknock
````
- при использовании composer.phar:
```bash
php composer.phar require andy87/knockknock
```
**Далее:** обновление зависимостей `composer update`Используя: файл `composer.json`
Открыть файл `composer.json`
В раздел, ключ `require` добавить строку
`"andy87/knockknock": "*"`
**Далее:** обновление зависимостей `composer update`Используя: подключение авто загрузчика
В месте, где необходимо использовать библиотеку, подключите авто загрузчик:
```php
require_once 'путь/к/корню/проекта/autoload.php';```
**Примечания:**
- Убедитесь, что путь к autoload.php правильный и соответствует структуре вашего проекта.- - - - -
___
Логика работы библиотеки (блок-схема)
### Простой пример работы.
```php
use andy87\knock_knock\lib\Method;
use andy87\knock_knock\lib\ContentType;
use andy87\knock_knock\core\Operator;
use andy87\knock_knock\core\Response;// Получаем компонент реализующий отправку запросов
$operator = new Operator( $_ENV['API_HOST'] )->disableSSL();/**
* Краткая форма записи (с не очевидным объектом запроса)
*/
$content = $operator->send( $operator->constructRequest(Method::GET, 'info/me') )->content;/**
* Детальная форма записи с дополнительными возможностями
*/
$request = $operator->constructRequest(Method::GET, 'info/me'); // Создаём объект запроса
$request->setCurlInfo([ CURLINFO_CONTENT_TYPE ]); // Назначаем опции cURL
$response = $operator->send($request); // Отправляем запрос и получаем ответ$content = $response->content; // Получаем данные ответа
$curlOptions = $response->request->curlOptions; // Получаем опции cURL$output = ( $curlOptions[CURLINFO_CONTENT_TYPE] === ContentType::JSON ) ? json_decode( $content ) : $content;
print_r( $output );
```
- - - - -
___
Базовый класс
_use [andy87\knock_knock\core\Operator](src/core/Operator.php);_
PHP Фасад\Адаптер для отправки запросов через ext cURL
ReadOnly свойства:
- **commonRequest**
- _Объект содержащий параметры, назначаемые всем исходящим запросам_
- **realRequest**
- _Используемый запрос_
- **eventHandlers**
- _Список обработчиков событий_
- **host**
- _Хост, на который будет отправляться запросы_
- **logs**
- _Список логов_Возможности/фичи:
- Настройки параметров запросов
- Защита данных от перезаписи
- Обработчики событий
- Инкапсуляция
- Singleton
- логирование
#### ВАЖНЫЙ МОМЕНТ!
- В классах применяется инкапсуляция, поэтому для доступа к свойствам компонентов используются ReadOnly свойства.
- `CURL_OPTIONS` по умолчанию пустые! В большинстве случаев, для получения валидных ответов, требуется задать необходимые настройки."Получение" объекта/экземпляра класса
Передавая параметры напрямую в конструктор:
```php
$operator = new Operator( $_ENV['API_HOST'], $commonRequestParams );
```
Применяя, паттерн Singleton:
```php
$operator = Operator::getInstance( $_ENV['API_HOST'], $commonRequestParams );
```
Методы возвращают объект(экземпляр класса `Operator`), принимая на вход два аргумента:
- `string $host` - хост
- `array $operatorConfig` - массив с настройками для всех исходящих запросов.При создании объекта `Operator` будет вызван метод `init()`, который запускает пользовательские инструкции.
После выполнения `init()` запускается обработчик события привязанный к ключу `EVENT_AFTER_CONSTRUCT`
Общие настройки запросов
Что бы указать настройки применяемые ко всем исходящим запросам,
при создании объекта `Operator` передаётся массив (ключ - значение), с необходимыми настройками.Пример настройки:
```php
// настройки для последующих исходящих запросов
$commonRequestParams = [
Request::SETUP_PROTOCO => $_ENV['API_PROTOCOL'],
Request::SETUP_CONTENT_TYPE => Request::CONTENT_TYPE_JSON,
Request::SETUP_CURL_OPTIONS => [
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true
]
];
// Получаем компонент для отправки запросов
$operator = new Operator( $_ENV['API_HOST'], $commonRequestParams );//Применяя, паттерн Singleton:
$operator = Operator::getInstance( $_ENV['API_HOST'], $commonRequestParams );
```
Доступные ключи для настройки(константы класса `Request`):- `SETUP_PROTOCOL`
- `SETUP_HOST`
- `SETUP_METHOD`
- `SETUP_HEADERS`
- `SETUP_CONTENT_TYPE`
- `SETUP_DATA`
- `SETUP_CURL_OPTIONS`
- `SETUP_CURL_INFO`Обработчики событий
Список событий
- `EVENT_AFTER_CONSTRUCT` после создания объекта knockKnock
- `EVENT_CREATE_REQUEST` после создания объекта запроса
- `EVENT_BEFORE_SEND` перед отправкой запроса
- `EVENT_CURL_Operator` перед отправкой curl запроса
- `EVENT_CREATE_RESPONSE` после создания объекта ответа
- `EVENT_AFTER_SEND` после получения ответаПример установки обработчиков событий
```php
$operator->setupEventHandlers([
Operator::EVENT_AFTER_CONSTRUCT => function( Operator $operator ) {
// ...
},
Operator::EVENT_CREATE_REQUEST => function( Operator $operator, Request $request ) {
// ...
},
Operator::EVENT_BEFORE_SEND => function( Operator $operator, Request $request ) {
// ...
},
Operator::EVENT_CURL_HANDLER => function( Operator $operator, resource $ch ) {
// ...
},
Operator::EVENT_CREATE_RESPONSE => function( Operator $operator, Response $response ) {
// ...
},
Operator::EVENT_AFTER_SEND => function( Operator $operator, Response $response ) {
// ...
}
]);
```
Первый аргумент - ключ события, второй - callback функция.Все callback функции принимают первым аргументом объект/экземпляр класса `Operaotr`.
Вторым аргументом передаётся объект/экземпляр класса в зависимости от события:
- `Request` - для событий `EVENT_CREATE_REQUEST`, `EVENT_BEFORE_SEND`
- `Response` - для событий `EVENT_CREATE_RESPONSE`, `EVENT_AFTER_SEND`- - - - -
___
Запрос
_use [andy87\knock_knock\core\Request](src/core/Request.php);_
Объект запроса, содержащий данные для отправки запроса.
ReadOnly свойства:
- **protocol** - _протокол_
- **host** - _хост_
- **endpoint** - _конечная точка_
- **method** - _метод_
- **headers** - _заголовки_
- **contentType** - _тип контента_
- **data** - _данные_
- **curlOptions** - _опции cURL_
- **curlInfo** - _информация cURL_
- **params** - _параметры запроса_
- **url** - _полный URL_
- **params** - _все свойства в виде массива_
- **fakeResponse** - _установленные фэйковые данные ответа_
- **errors** - _лог ошибок_Создание объекта запроса
Передавая параметры напрямую в конструктор:
```php
$request = new Request( 'info/me', [
Request::METHOD => Method::POST,
Request::DATA => [ 'client_id' => 34 ],
Request::HEADERS => [ 'api-secret-key' => $_ENV['API_SECRET_KEY'] ],
Request::CURL_OPTIONS => [ CURLOPT_TIMEOUT => 10 ],
Request::CURL_INFO => [
CURLINFO_CONTENT_TYPE,
CURLINFO_HEADER_SIZE,
CURLINFO_TOTAL_TIME
],
Request::CONTENT_TYPE => ContentType::FORM_DATA,
]);
```
Методом, который вызывает _callback_ функцию, привязанную к ключу `EVENT_CREATE_REQUEST`
```php
$request = $operator->constructRequest(Method::GET, 'info/me', [
Request::METHOD => Method::POST,
Request::DATA => [ 'client_id' => 45 ],
Request::HEADERS => [ 'api-secret-key' => $_ENV['API_SECRET_KEY'] ],
Request::CURL_OPTIONS => [ CURLOPT_TIMEOUT => 10 ],
Request::CURL_INFO => [
CURLINFO_CONTENT_TYPE,
CURLINFO_HEADER_SIZE,
CURLINFO_TOTAL_TIME
],
Request::CONTENT_TYPE => ContentType::FORM_DATA,
]);
```
Клонируя существующий объект запроса:
```php
$request = $operator->constructRequest(Method::GET, 'info/me');$response = $operator->send($request);
//Клонирование объекта запроса (без статуса отправки)
$cloneRequest = $request->clone();// Отправка клона запроса
$response = $operator->setupRequest( $cloneRequest )->send();
```
Назначение/Изменение/Получение отдельных параметров запроса (set/get)Таблица set/get методов для взаимодействия с отдельными свойствами запроса
| Параметр | Сеттер | Геттер | Информация |
|-----------------|---------------------------------------|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Протокол | setProtocol( string $protocol ) | getProtocol(): string | протоколы |
| Хост | setHost( string $host ) | getHost(): string | --- |
| Endpoint | setEndpoint( string $url ) | getEndpoint(): string | --- |
| Метод | setMethod( string $method ) | getMethod(): string | методы |
| Заголовки | setHeaders( array $headers ) | getHeaders(): array | заголовки |
| Тип контента | setContentType( string $contentType ) | getContentType(): string | Тип контента |
| Данные | setData( mixed $data ) | getData(): mixed | --- |
| Опции cURL | setCurlOptions( array $curlOptions ) | getCurlOptions(): array | Опции cURL |
| Информация cURL | setCurlInfo( array $curlInfo ) | getCurlInfo(): array | Информация cURL |
| Фэйковый ответ | setFakeResponse( array $response ) | getFakeResponse(): array | |```php
$request = $operator->constructRequest(Method::GET, 'info/me');$request->setMethod( Method::GET );
$request->setData(['client_id' => 67]);
$request->setHeaders(['api-secret-key' => 'secretKey67']);
$request->setCurlOptions([
CURLOPT_TIMEOUT => 10,
CURLOPT_RETURNTRANSFER => true
]);
$request->setCurlInfo([
CURLINFO_CONTENT_TYPE,
CURLINFO_HEADER_SIZE,
CURLINFO_TOTAL_TIME
]);
$request->setContentType( ContentType::JSON );$protocol = $request->getPrococol(); // String
$host = $request->getHost(); // String
// ... аналогичным образом доступны и другие подобные методы для получения свойств запроса
```Назначение запроса с переназначением свойств
```php
$operator->setupRequest( $request, [
Request::SETUP_HOST => $_ENV['API_HOST'],
Request::SETUP_HEADERS => [
'api-secret' => $_ENV['API_SECRET_KEY']
],
]);
```
`setupRequest( Request $request, array $options = [] ): self`##### addError( string $error )
Добавление ошибки в лог ошибок
```php
$request = $operator->constructRequest(Method::GET, 'info/me');$request->addError('Ошибка!');
```
- - - - -
___
Ответ
_use [andy87\knock_knock\core\Response](src/core/Response.php);_
Объект ответа, содержащий данные ответа на запрос.
ReadOnly свойства
- **content**
- _данные ответа_
- **httpCode**
- _код ответа_
- **request**
- _объект запроса, содержащий данные о запросе_
- **curlOptions**
- _быстрый доступ к request->curlOptions_
- **curlInfo**
- _быстрый доступ к request->curlInfo_Создание объекта ответа
Передавая параметры напрямую в конструктор:
```php
$response = new Response('{"id" => 806034, "name" => "and_y87"}', 200 );
```
Методом, который вызывает _callback_ функцию, привязанную к ключу `EVENT_CREATE_RESPONSE`
```php
$response = $operator->constructResponse([
Response::CONTENT => [
'id' => 806034,
'name' => 'and_y87'
],
Response::HTTP_CODE => 400,
], $request );
```
`constructResponse( array $responseParams, ?Request $request = null ): Response`Отправка запроса
`send( ?Request $request = null ): Response`
Вызов возвращает объект/экземпляр класса `Response`.
Срабатывают callback функции, привязанные к ключам:
- `EVENT_AFTER_SEND`
- `EVENT_CREATE_RESPONSE`
- `EVENT_BEFORE_SEND`
- `EVENT_CURL_HANDLER````php
$operator = new Operator( $_ENV['API_HOST'] );
$request = $operator->constructRequest(Method::GET, 'info/me');
$response = $operator->send($request);// Аналог
$operator = new Operator( $_ENV['API_HOST'] );
$response = $operator->send( $operator->constructRequest(Method::GET, 'info/me') );
```
Нельзя повторно отправить запрос, выбрасывается исключение `RequestCompleteException`.
Для повторной отправки запроса, необходимо создать новый объект запроса и использовать его:
```php
$operator = new Operator( $_ENV['API_HOST'] );
$request = $operator->constructRequest(Method::GET, 'info/me');
$response = $operator->send($request);// повторная отправка запроса
$response = $operator->send($request->clone());
```Отправка запроса с фэйковым ответом
```php
// параметры возвращаемого ответа
$fakeResponse = [
Response::HTTP_CODE => 200,
Response::CONTENT => '{"id" => 8060345, "nickName" => "and_y87"}'
];
$request->setFakeResponse( $fakeResponse );$response = $operator->send( $request );
```
объект `$response` будет содержать в свойствах `content`, `httpCode` данные переданные в аргументе `$fakeResponse`Данные в ответе
В созданный объект `Response`, чей запрос не был отправлен, разрешено задавать данные, используя методы группы `set`.
```php
$response = $operator->send($request);$response
->setHttpCode(200)
->setContent('{"id" => 8060345, "nickName" => "and_y87"}');
```
**Внимание!** Если данные в объекте уже существуют, повторно задать их нельзя выбрасывается `ParamUpdateException`.
В случае необходимости заменить данные, используется вызов метода `replace( string $key, mixed $value )` см. далее
Подмена данных
Это сделано для явного действия, когда необходимо заменить данные в объекте `Response`.```php
$response = $operator->send($request);$response
->replace( Response::HTTP_CODE, 200 )
->replace( Response::CONTENT, '{"id" => 8060345, "nickName" => "and_y87"}' );
```Данные запроса из ответа
Для получения из объекта `Response` данных запроса, необходимо обратиться к ReadOnly свойству `request`
и далее взаимодействовать с ним аналогично объекту `Request`
```php
$operator = new Operator( $_ENV['API_HOST'] );
$response = $operator->setRequest( $operator->constructRequest(Method::GET, 'info/me') )->send();// Получение компонента запроса
$request = $response->request;$method = $request->method; // получение метода запроса
```Получения свойств cURL запроса
```php
$operator = new Operator( $_ENV['API_HOST'] );
$response = $operator->setRequest( $operator->constructRequest(Method::GET, 'info/me') )->send();$response->request;
// Получение свойств через объект запроса
$curlOptions = $response->request->curlOption;
$curlInfo = $response->request->curlInfo;//Вариант с использованием быстрого доступа
$curlOptions = $response->curlOption;
$curlInfo = $response->curlInfo;
```asArray()
Преобразование в массив.
- преобразование данных ответа на запрос `asArray()`
- преобразование всего объекта в массив `asArray(true)`
```php
$response = $operator->send($request)->asArray(); // $response
$array = $response->content; // Array$response
```
##### addError( string $error )
Добавление ошибки в лог ошибок
```php
$request = $operator->constructRequest(Method::GET, 'info/me');$response = $operator->send($request);
$response->addError('Ошибка!');
```
- - - - -
___
- - - - -
Дополнительные возможности
SSL
Функционал включения/отключения SSL верификации в объектах `Operaotr` & `Request`.
В `curlOptions` добавляется ключ `CURLOPT_SSL_VERIFYPEER` и `CURLOPT_SSL_VERIFYHOST`.
`->disableSSL( bool $verifyPeer = false, int $verifyHost = 0 );`
`->enableSSL( bool $verifyPeer = true, int $verifyHost = 2 );``Operaotr` - для всех запросов
```php
$operator = new Operator( $_ENV['API_HOST'] );
$operator->disableSSL();$request = $operator->constructRequest(Method::GET, 'info/me');
$response = $operator->setupRequest( $request )->send();
````Request` - для конкретного запроса
```php
$operator = new Operator( $_ENV['API_HOST'] )->disableSSL();$request = $operator->constructRequest(Method::GET, 'info/me');
$request->enableSSL();$response = $operator->setupRequest( $request )->send();
```Cookie
В объекте `Operaotr` имеется функционал использования cookie.
`Operaotr` - для всех запросов
```php
$operator = new Operator( $_ENV['API_HOST'] );$cookie = $_ENV['COOKIE'];
$jar = $_ENV['COOKIE_JAR'];$operator->useCookie( $cookie, $jar );
```
`$operator->useCookie( string $cookie, string $jar, ?string $file = null )`
по умолчанию `$file = null` и `$file` приравнивается к `$jar`Логирование
Добавление сообщений во внутренний массив `logs`
```php
$operator = new Operator( $_ENV['API_HOST'] );$operator->addLog( 'Какое то сообщение' );
```
`$operator->addLog( string $message )`- - - - -
___
- - - - -
Расширения на основе базового класса
KnockKnockOctopus
Класс с функционалом простой реализации отправки запросов и минимальными настройками
Доступные методы.
| get() | post() | put() | patch() | delete() | head() | options() | trace() |
|-------|--------|-------|---------|----------|--------|-----------|---------|Каждый метод принимает два аргумента:
| Аргумент | Тип | Обязательный | Описание |
|:----------|:-------:|:-------------:|:-------------------------------|
| $endpoint | string | Да | URL запроса (без хоста) |
| $params | array | Нет | Данные запроса в виде массива |
_P.S. host задаётся в конструкторе_Простой пример использования
```php
$knockKnockOctopus = new KnockKnockOctopus($_ENV['API_URL']);$knockKnockOctopus->get( '/profile', [ 'id' => 806034 ] ); //GET запрос
$knockKnockOctopus->post( '/new', [ //POST запрос
'name' => 'Новая новость',
'content' => 'Текст новости'
]);
```- - - - -
KnockKnockSecurity
Расширяет класс [KnockKnockOctopus](docs/KnockKnock/KnockKnockOctopus.md), предоставляя доступ к функционалу для простой и
быстрой реализации авторизации, и настройки запросов.```php
$knockKnockSecurity = new KnockKnockSecurity($_ENV['API_URL']);// Настройка параметров запроса по умолчанию
$knockKnockSecurity
->disableSSL()
->setupAuthorization( KnockKnockSecurity::TOKEN_BEARER, 'token' )
->setupHeaders([ 'X-Api-Key' => $_ENV['X_API_KEY'] ])
->setupContentType( ContentType::JSON )
->on( Operator::EVENT_AFTER_SEND, function( Operator $operator, Response $response ) =>
{
$logFilePath = $_SERVER['DOCUMENT_ROOT'] . '/api_log.txt';file_put_contents( $logFilePath, $response->content, FILE_APPEND );
});// Получение ответа на запрос методом `patch`
$responsePatch = $knockKnockSecurity->patch( 'product', [
'price' => 1000
]);$product = $responsePatch->asArray();
$price = $product['price'];
// Изменение типа контента на `application/json`, для следующего запроса
$knockKnockSecurity->useContentType( ContentType::JSON );// Отправка POST запроса и получение ответа
$responsePost = $knockKnockSecurity->post( 'category', [
'name' => 'Фреймворки'
]);$response = json_decode( $responsePost->content );
$category_id = $response->id;
```
- - - - -
___
- - - - -
Custom реализация
Custom реализация Базового класса, к примеру с добавлением логирования работающим "под капотом"
```php
class KnockKnockYandex extends Operator
{
private const LOGGER = 'logger';private string $host = 'https://api.yandex.ru/'
private string $contentType = ContentType::JSON
private YandexLogger $logger;
/**
* @return void
*/
public function init(): void
{
$this->setupYandexLoggerEventHandlers();
}
/**
* @param array $callbacks
*
* @return self
*/
private function setupYandexLoggerEventHandlers( array $callbacks ): self
{
$this->on( self::AFTER_CREATE_REQUEST, function( Request $request ) =>
{
$logData = $this->getLogDataByRequest( $request );$this->addYandexLog( $logData );
};$this->on(self::EVENT_AFTER_SEND, function( Response $response ) =>
{
$logData = $this->getLogDataByRequest( $response->request );$this->addYandexLog( $logData );
};
}/**
* @param Request $request
*
* @return array
*/
private function getLogDataByRequest( Request $request ): array
{
return $request->getParams();
}/**
* @param array $logData
*
* @return void
*/
private function addYandexLog( array $logData ): bool
{
return $logger->log( $logData );
}
}```
Пример использования custom реализации```php
$knockKnockYandex = KnockKnockYandex::getInstanсe( $_ENV['API_HOST'], [
KnockKnockYandex::LOGGER => new YandexLogger(),
]);$response = $knockKnockYandex->setupRequest( 'profile', [
Request::METHOD => Method::PATCH,
Request::DATA => [ 'city' => 'Moscow' ],
]); // Логирование `afterCreateRequest`$response = $knockKnockYandex->send(); // Логирование `afterSend`
```- - - - -
___
- - - - -
Тесты
- tests: 100+
- assertions: 350+
Запуск тестов:Нативный
```bash
vendor/bin/phpunit
```
Информационный
```bash
vendor/bin/phpunit --testdox
```
С логированием
```bash
vendor/bin/phpunit --log-junit "tests/logs/phpunit.xml"
```Лицензия
https://github.com/andy87/KnockKnock под лицензией CC BY-SA 4.0
Для получения дополнительной информации смотрите http://creativecommons.org/licenses/by-sa/4.0/
Свободно для не коммерческого использования
С указанием авторства для коммерческого использования[Packagist](https://packagist.org/packages/andy87/knockknock)