add route to search instances by field value
This commit is contained in:
@@ -13,6 +13,8 @@ use Api\Core\RateLimiter\FileRateLimiter;
|
||||
use Api\Core\RateLimiter\InMemoryRateLimiter;
|
||||
use Api\Core\Log\LoggerFactory;
|
||||
use ElixForms\ElixFormsClient;
|
||||
use ElixForms\Auth\ElixFormsApiClient;
|
||||
use ElixForms\Auth\ElixFormsAuthenticationClient;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
$container = new Container();
|
||||
@@ -67,6 +69,21 @@ $container->singleton(ElixFormsClient::class, function($c) {
|
||||
return new ElixFormsClient($baseUrl);
|
||||
});
|
||||
|
||||
$container->singleton(ElixFormsAuthenticationClient::class, function($c) {
|
||||
$config = $c->make(Config::class);
|
||||
|
||||
return new ElixFormsAuthenticationClient($config->get('elixforms_api_base_url'));
|
||||
});
|
||||
|
||||
$container->singleton(ElixFormsApiClient::class, function($c) {
|
||||
$config = $c->make(Config::class);
|
||||
|
||||
return new ElixFormsApiClient(
|
||||
$config->get('elixforms_api_base_url'),
|
||||
$c->make(HttpClient::class)
|
||||
);
|
||||
});
|
||||
|
||||
// If you have other services, bind them here, for example:
|
||||
// $container->singleton(SomeService::class, function($c) {
|
||||
// return new SomeService($c->make(LoggerInterface::class), ...);
|
||||
|
||||
+3
-6
@@ -87,12 +87,9 @@ if (strpos($request->path(), '/api/') === 0) {
|
||||
}
|
||||
|
||||
// register routes (path without version prefix)
|
||||
// $router->get('/users/index', 'UsersController@index');
|
||||
// $router->post('/users/create', 'UsersController@create');
|
||||
// $router->get('/example/test', 'ExampleController@test');
|
||||
// $router->get('/dipendenti/cerca', 'DipendentiController@search');
|
||||
$router->get('/api/contratti/cerca', 'ContrattiController@search');
|
||||
$router->get('/api/dipendenti/cerca', 'DipendentiController@search');
|
||||
$router->get('/contratti/cerca', 'ContrattiController@search');
|
||||
$router->get('/dipendenti/cerca', 'DipendentiController@search');
|
||||
$router->get('/elixforms/instances/search', 'ElixFormsController@searchInstances');
|
||||
|
||||
// Rate limiting by IP address
|
||||
$key = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
namespace Api\Controllers\V1;
|
||||
|
||||
use Api\Core\Config;
|
||||
use Api\Core\Request;
|
||||
use Api\Core\Response;
|
||||
use ElixForms\Auth\ElixFormsApiClient;
|
||||
use ElixForms\Auth\ElixFormsAuthenticationClient;
|
||||
use ElixForms\Exceptions\ElixFormsException;
|
||||
|
||||
class ElixFormsController
|
||||
{
|
||||
private ElixFormsAuthenticationClient $authenticationClient;
|
||||
private ElixFormsApiClient $apiClient;
|
||||
private Config $config;
|
||||
|
||||
public function __construct(
|
||||
ElixFormsAuthenticationClient $authenticationClient,
|
||||
ElixFormsApiClient $apiClient,
|
||||
Config $config
|
||||
) {
|
||||
$this->authenticationClient = $authenticationClient;
|
||||
$this->apiClient = $apiClient;
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function searchInstances(Request $req, Response $res)
|
||||
{
|
||||
$query = $req->query();
|
||||
$moduleTag = $this->requiredString($query, 'moduleTag');
|
||||
$fieldName = $this->requiredString($query, 'fieldName');
|
||||
$fieldValue = $this->requiredString($query, 'fieldValue');
|
||||
$exportGroup = $this->optionalNonEmptyString($query, 'exportGroup', 'API');
|
||||
|
||||
if ($moduleTag === null || $fieldName === null || $fieldValue === null || $exportGroup === null) {
|
||||
return $res->json([
|
||||
'error' => 'moduleTag, fieldName e fieldValue sono obbligatori; exportGroup, se specificato, deve essere una stringa non vuota.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$username = $this->config->secret('elixforms_api_username');
|
||||
$password = $this->config->secret('elixforms_api_password');
|
||||
|
||||
if (!is_string($username) || trim($username) === '' || !is_string($password) || $password === '') {
|
||||
throw new ElixFormsException('Credenziali elixForms non configurate.');
|
||||
}
|
||||
|
||||
$token = $this->authenticationClient->login($username, $password);
|
||||
$instances = $this->apiClient->lookupByStatus($moduleTag, $token, $username);
|
||||
$matchingInstances = [];
|
||||
|
||||
foreach ($instances as $instance) {
|
||||
if (!is_array($instance)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$requestId = $this->requestId($instance);
|
||||
if ($requestId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$exportTags = $this->apiClient->getExportTags(
|
||||
$requestId,
|
||||
$moduleTag,
|
||||
$token,
|
||||
$username,
|
||||
$exportGroup
|
||||
);
|
||||
|
||||
foreach ($exportTags as $exportTag) {
|
||||
if (!is_array($exportTag) || !isset($exportTag['name'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = (string) $exportTag['name'];
|
||||
$value = isset($exportTag['value']) ? (string) $exportTag['value'] : '';
|
||||
|
||||
if (strcasecmp($name, $fieldName) === 0 && stripos($value, $fieldValue) !== false) {
|
||||
$matchingInstances[] = $instance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $res->json($matchingInstances);
|
||||
}
|
||||
|
||||
private function requiredString(array $values, string $key): ?string
|
||||
{
|
||||
if (!isset($values[$key]) || !is_string($values[$key])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = trim($values[$key]);
|
||||
|
||||
return $value === '' ? null : $value;
|
||||
}
|
||||
|
||||
private function optionalNonEmptyString(array $values, string $key, string $default): ?string
|
||||
{
|
||||
if (!array_key_exists($key, $values)) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if (!is_string($values[$key])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$value = trim($values[$key]);
|
||||
|
||||
return $value === '' ? null : $value;
|
||||
}
|
||||
|
||||
private function requestId(array $instance)
|
||||
{
|
||||
foreach (['idDomanda', 'requestId', 'idRequest'] as $key) {
|
||||
if (isset($instance[$key]) && (is_int($instance[$key]) || is_string($instance[$key]))) {
|
||||
return $instance[$key];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
namespace ElixForms\Auth;
|
||||
|
||||
use Api\Core\HttpClient;
|
||||
use ElixForms\Exceptions\ElixFormsException;
|
||||
|
||||
class ElixFormsApiClient
|
||||
{
|
||||
private string $baseUrl;
|
||||
private HttpClient $httpClient;
|
||||
|
||||
public function __construct(string $baseUrl, HttpClient $httpClient)
|
||||
{
|
||||
$this->baseUrl = rtrim($baseUrl, '/');
|
||||
$this->httpClient = $httpClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restituisce le istanze del modulo, opzionalmente filtrate per stato.
|
||||
* I flag di ElixFormsRequestStatus possono essere combinati con l'operatore |.
|
||||
*
|
||||
* @return array<int,array<string,mixed>>
|
||||
*/
|
||||
public function lookupByStatus(
|
||||
string $moduleTag,
|
||||
string $authToken,
|
||||
string $username,
|
||||
?int $status = null
|
||||
): array
|
||||
{
|
||||
$queryParts = [];
|
||||
if ($status !== null) {
|
||||
foreach (ElixFormsRequestStatus::toApiValues($status) as $statusValue) {
|
||||
$queryParts[] = 'requestStatus=' . rawurlencode($statusValue);
|
||||
}
|
||||
}
|
||||
$queryParts[] = 'moduleTag=' . rawurlencode($moduleTag);
|
||||
|
||||
$url = $this->baseUrl . '/eF/api/request/lookup/by-status?' . implode('&', $queryParts);
|
||||
$payload = $this->getJson($url, $authToken, $username, 'LookupByStatus');
|
||||
$requests = $payload['value']['requests'] ?? [];
|
||||
|
||||
if (!is_array($requests)) {
|
||||
throw new ElixFormsException('Risposta LookupByStatus non valida: requests deve essere un array.');
|
||||
}
|
||||
|
||||
return array_values($requests);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|string $requestId
|
||||
* @return array<int,array{name?:mixed,value?:mixed}>
|
||||
*/
|
||||
public function getExportTags(
|
||||
$requestId,
|
||||
string $moduleTag,
|
||||
string $authToken,
|
||||
string $username,
|
||||
string $exportGroup = 'API'
|
||||
): array
|
||||
{
|
||||
$exportGroup = trim($exportGroup);
|
||||
if ($exportGroup === '') {
|
||||
throw new \InvalidArgumentException('exportGroup deve essere una stringa non vuota.');
|
||||
}
|
||||
|
||||
$url = sprintf(
|
||||
'%s/eF/services/api/request/%s/view/_DEFAULT/exportTags/get/v1?moduleTag=%s&exportGroup=%s',
|
||||
$this->baseUrl,
|
||||
rawurlencode((string) $requestId),
|
||||
rawurlencode($moduleTag),
|
||||
rawurlencode($exportGroup)
|
||||
);
|
||||
$payload = $this->getJson($url, $authToken, $username, 'GetExportTags');
|
||||
$exportTags = $payload['value']['exportTags'] ?? [];
|
||||
|
||||
if (!is_array($exportTags)) {
|
||||
throw new ElixFormsException('Risposta GetExportTags non valida: exportTags deve essere un array.');
|
||||
}
|
||||
|
||||
return array_values($exportTags);
|
||||
}
|
||||
|
||||
private function getJson(
|
||||
string $url,
|
||||
string $authToken,
|
||||
string $username,
|
||||
string $operation
|
||||
): array {
|
||||
$response = $this->httpClient->get($url, [
|
||||
'Authorization' => 'Bearer ' . $authToken,
|
||||
'Accept' => 'application/json',
|
||||
'x-requested-with' => 'XMLHttpRequest',
|
||||
'x-api-username' => $username,
|
||||
]);
|
||||
|
||||
$status = $response['status'] ?? 500;
|
||||
if ($status !== 200) {
|
||||
throw new ElixFormsException(sprintf(
|
||||
'Errore durante %s. HTTP Status: %d',
|
||||
$operation,
|
||||
$status
|
||||
));
|
||||
}
|
||||
|
||||
$payload = $response['json'] ?? null;
|
||||
$jsonError = JSON_ERROR_NONE;
|
||||
if (!is_array($payload) && isset($response['body']) && is_string($response['body'])) {
|
||||
$payload = json_decode($response['body'], true);
|
||||
$jsonError = json_last_error();
|
||||
}
|
||||
|
||||
if (!is_array($payload) || $jsonError !== JSON_ERROR_NONE) {
|
||||
throw new ElixFormsException(sprintf(
|
||||
'Risposta non valida da %s: atteso JSON.',
|
||||
$operation
|
||||
));
|
||||
}
|
||||
|
||||
$globalStatus = $payload['value']['globalStatus'] ?? null;
|
||||
if ($globalStatus === 'ERROR') {
|
||||
$description = $payload['value']['description'] ?? 'errore non specificato';
|
||||
throw new ElixFormsException(sprintf(
|
||||
'%s ha restituito un errore: %s',
|
||||
$operation,
|
||||
$description
|
||||
));
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ class ElixFormsAuthenticationClient {
|
||||
private $baseUrl;
|
||||
private $httpClient;
|
||||
|
||||
public function __construct(string $baseUrl, Client $httpClient = null) {
|
||||
public function __construct(string $baseUrl, ?Client $httpClient = null) {
|
||||
$this->baseUrl = rtrim($baseUrl, '/');
|
||||
$this->httpClient = $httpClient ?? new Client(['timeout' => 10.0, 'http_errors' => false]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
namespace ElixForms\Auth;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Enum-like di flag combinabili per gli stati delle istanze elixForms.
|
||||
*
|
||||
* Esempio: ElixFormsRequestStatus::IN_PROGRESS | ElixFormsRequestStatus::PROCESSED
|
||||
*/
|
||||
final class ElixFormsRequestStatus
|
||||
{
|
||||
public const IN_PROGRESS = 1;
|
||||
public const SUBMITTED = 2;
|
||||
public const PROCESSED = 4;
|
||||
public const ALL = self::IN_PROGRESS | self::SUBMITTED | self::PROCESSED;
|
||||
|
||||
private const API_VALUES = [
|
||||
self::IN_PROGRESS => 'IN_PROGRESS',
|
||||
self::SUBMITTED => 'SUBMITTED',
|
||||
self::PROCESSED => 'PROCESSED',
|
||||
];
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int,string>
|
||||
*/
|
||||
public static function toApiValues(int $status): array
|
||||
{
|
||||
if ($status <= 0 || ($status & ~self::ALL) !== 0) {
|
||||
throw new InvalidArgumentException('La combinazione di stati elixForms non è valida.');
|
||||
}
|
||||
|
||||
$values = [];
|
||||
foreach (self::API_VALUES as $flag => $apiValue) {
|
||||
if (($status & $flag) === $flag) {
|
||||
$values[] = $apiValue;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use Api\Core\HttpClient;
|
||||
use ElixForms\Auth\ElixFormsApiClient;
|
||||
use ElixForms\Auth\ElixFormsRequestStatus;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ElixFormsApiClientTest extends TestCase
|
||||
{
|
||||
public function testLookupByStatusOmitsStatusWhenItIsNull(): void
|
||||
{
|
||||
$httpClient = new class extends HttpClient {
|
||||
public string $url = '';
|
||||
public array $headers = [];
|
||||
|
||||
public function get(string $url, array $headers = [])
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->headers = $headers;
|
||||
|
||||
return [
|
||||
'status' => 200,
|
||||
'json' => [
|
||||
'value' => [
|
||||
'globalStatus' => 'OK',
|
||||
'requests' => [['requestId' => 123]],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
};
|
||||
$client = new ElixFormsApiClient('https://example.test', $httpClient);
|
||||
|
||||
$requests = $client->lookupByStatus('MODULO TEST', 'token', 'user');
|
||||
|
||||
self::assertSame([['requestId' => 123]], $requests);
|
||||
self::assertStringNotContainsString('requestStatus=', $httpClient->url);
|
||||
self::assertStringContainsString('moduleTag=MODULO%20TEST', $httpClient->url);
|
||||
self::assertSame('Bearer token', $httpClient->headers['Authorization']);
|
||||
self::assertSame('user', $httpClient->headers['x-api-username']);
|
||||
}
|
||||
|
||||
public function testLookupByStatusExpandsCombinedFlags(): void
|
||||
{
|
||||
$httpClient = new class extends HttpClient {
|
||||
public string $url = '';
|
||||
|
||||
public function get(string $url, array $headers = [])
|
||||
{
|
||||
$this->url = $url;
|
||||
|
||||
return [
|
||||
'status' => 200,
|
||||
'json' => [
|
||||
'value' => [
|
||||
'globalStatus' => 'OK',
|
||||
'requests' => [],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
};
|
||||
$client = new ElixFormsApiClient('https://example.test', $httpClient);
|
||||
|
||||
$client->lookupByStatus(
|
||||
'MODULO',
|
||||
'token',
|
||||
'user',
|
||||
ElixFormsRequestStatus::IN_PROGRESS | ElixFormsRequestStatus::PROCESSED
|
||||
);
|
||||
|
||||
self::assertStringContainsString('requestStatus=IN_PROGRESS', $httpClient->url);
|
||||
self::assertStringNotContainsString('requestStatus=SUBMITTED', $httpClient->url);
|
||||
self::assertStringContainsString('requestStatus=PROCESSED', $httpClient->url);
|
||||
}
|
||||
|
||||
public function testRequestStatusRejectsUnknownFlags(): void
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
ElixFormsRequestStatus::toApiValues(8);
|
||||
}
|
||||
|
||||
public function testGetExportTagsSupportsVendorJsonContentTypeResponses(): void
|
||||
{
|
||||
$httpClient = new class extends HttpClient {
|
||||
public string $url = '';
|
||||
|
||||
public function get(string $url, array $headers = [])
|
||||
{
|
||||
$this->url = $url;
|
||||
|
||||
return [
|
||||
'status' => 200,
|
||||
'body' => json_encode([
|
||||
'value' => [
|
||||
'globalStatus' => 'OK',
|
||||
'exportTags' => [
|
||||
['name' => 'contratto.id', 'value' => 'ABC-123'],
|
||||
],
|
||||
],
|
||||
]),
|
||||
'json' => null,
|
||||
];
|
||||
}
|
||||
};
|
||||
$client = new ElixFormsApiClient('https://example.test/', $httpClient);
|
||||
|
||||
$tags = $client->getExportTags(42, 'MODULO', 'token', 'user');
|
||||
|
||||
self::assertSame(
|
||||
[['name' => 'contratto.id', 'value' => 'ABC-123']],
|
||||
$tags
|
||||
);
|
||||
self::assertSame(
|
||||
'https://example.test/eF/services/api/request/42/view/_DEFAULT/exportTags/get/v1?moduleTag=MODULO&exportGroup=API',
|
||||
$httpClient->url
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetExportTagsUsesTheProvidedExportGroup(): void
|
||||
{
|
||||
$httpClient = new class extends HttpClient {
|
||||
public string $url = '';
|
||||
|
||||
public function get(string $url, array $headers = [])
|
||||
{
|
||||
$this->url = $url;
|
||||
|
||||
return [
|
||||
'status' => 200,
|
||||
'json' => [
|
||||
'value' => [
|
||||
'globalStatus' => 'OK',
|
||||
'exportTags' => [],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
};
|
||||
$client = new ElixFormsApiClient('https://example.test', $httpClient);
|
||||
|
||||
$client->getExportTags(42, 'MODULO', 'token', 'user', 'REPORT ORE');
|
||||
|
||||
self::assertStringContainsString('exportGroup=REPORT%20ORE', $httpClient->url);
|
||||
}
|
||||
|
||||
public function testGetExportTagsRejectsAnEmptyExportGroup(): void
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
$httpClient = new HttpClient();
|
||||
$client = new ElixFormsApiClient('https://example.test', $httpClient);
|
||||
$client->getExportTags(42, 'MODULO', 'token', 'user', ' ');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
namespace Tests\Unit;
|
||||
|
||||
use Api\Controllers\V1\ElixFormsController;
|
||||
use Api\Core\Config;
|
||||
use Api\Core\Request;
|
||||
use Api\Core\Response;
|
||||
use ElixForms\Auth\ElixFormsApiClient;
|
||||
use ElixForms\Auth\ElixFormsAuthenticationClient;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class ElixFormsControllerTest extends TestCase
|
||||
{
|
||||
public function testSearchInstancesReturnsOnlyMatchingInstances(): void
|
||||
{
|
||||
$authenticationClient = new class extends ElixFormsAuthenticationClient {
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function login(string $username, string $password): string
|
||||
{
|
||||
return 'token';
|
||||
}
|
||||
};
|
||||
$apiClient = new class extends ElixFormsApiClient {
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function lookupByStatus(
|
||||
string $moduleTag,
|
||||
string $authToken,
|
||||
string $username,
|
||||
?int $status = null
|
||||
): array
|
||||
{
|
||||
return [
|
||||
['idDomanda' => 10],
|
||||
['requestId' => 20],
|
||||
['idRequest' => 30],
|
||||
];
|
||||
}
|
||||
|
||||
public function getExportTags(
|
||||
$requestId,
|
||||
string $moduleTag,
|
||||
string $authToken,
|
||||
string $username,
|
||||
string $exportGroup = 'API'
|
||||
): array
|
||||
{
|
||||
if ($exportGroup !== 'CUSTOM') {
|
||||
throw new \RuntimeException('exportGroup non inoltrato al client.');
|
||||
}
|
||||
|
||||
$values = [
|
||||
10 => 'Nessuna corrispondenza',
|
||||
20 => 'Il contratto ABC-123 è presente',
|
||||
30 => 'Altro valore',
|
||||
];
|
||||
|
||||
return [[
|
||||
'name' => 'contratto.id',
|
||||
'value' => $values[$requestId],
|
||||
]];
|
||||
}
|
||||
};
|
||||
$config = new class extends Config {
|
||||
public function secret($key, $default = null)
|
||||
{
|
||||
return $key === 'elixforms_api_username' ? 'user' : 'password';
|
||||
}
|
||||
};
|
||||
$request = new class extends Request {
|
||||
public function query()
|
||||
{
|
||||
return [
|
||||
'moduleTag' => 'MODULO',
|
||||
'fieldName' => 'contratto.id',
|
||||
'fieldValue' => 'abc-123',
|
||||
'exportGroup' => ' CUSTOM ',
|
||||
];
|
||||
}
|
||||
};
|
||||
$response = new CapturingResponse();
|
||||
$controller = new ElixFormsController($authenticationClient, $apiClient, $config);
|
||||
|
||||
try {
|
||||
$controller->searchInstances($request, $response);
|
||||
self::fail('La risposta avrebbe dovuto interrompere il flusso del test.');
|
||||
} catch (CapturedResponseException $exception) {
|
||||
self::assertSame(200, $exception->status);
|
||||
self::assertSame([['requestId' => 20]], $exception->payload);
|
||||
}
|
||||
}
|
||||
|
||||
public function testSearchInstancesRejectsMissingParameters(): void
|
||||
{
|
||||
$authenticationClient = new class extends ElixFormsAuthenticationClient {
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
};
|
||||
$apiClient = new class extends ElixFormsApiClient {
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
};
|
||||
$config = new Config();
|
||||
$request = new class extends Request {
|
||||
public function query()
|
||||
{
|
||||
return ['moduleTag' => 'MODULO'];
|
||||
}
|
||||
};
|
||||
$controller = new ElixFormsController($authenticationClient, $apiClient, $config);
|
||||
|
||||
try {
|
||||
$controller->searchInstances($request, new CapturingResponse());
|
||||
self::fail('La risposta avrebbe dovuto interrompere il flusso del test.');
|
||||
} catch (CapturedResponseException $exception) {
|
||||
self::assertSame(400, $exception->status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class CapturingResponse extends Response
|
||||
{
|
||||
public function json($data, $status = 200)
|
||||
{
|
||||
throw new CapturedResponseException($data, $status);
|
||||
}
|
||||
}
|
||||
|
||||
final class CapturedResponseException extends \RuntimeException
|
||||
{
|
||||
public $payload;
|
||||
public int $status;
|
||||
|
||||
public function __construct($payload, int $status)
|
||||
{
|
||||
parent::__construct('Response captured');
|
||||
$this->payload = $payload;
|
||||
$this->status = $status;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user