forked from urvishpatelce/lxd-app
Compare commits
3 Commits
627d462a8e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 78b8a25546 | |||
| bd32f43c9e | |||
| a3f5b5a0cf |
2
api/.env
2
api/.env
@ -6,4 +6,4 @@ LXD_CLIENT_CERT=/etc/ssl/lxdapp/client.crt
|
|||||||
LXD_CLIENT_KEY=/etc/ssl/lxdapp/client.key
|
LXD_CLIENT_KEY=/etc/ssl/lxdapp/client.key
|
||||||
LXD_IMAGE_FINGERPRINT=2edfd84b1396
|
LXD_IMAGE_FINGERPRINT=2edfd84b1396
|
||||||
AUTH_KEY=R9kX2HFA7ZjLdVYm8TsQWpCeNuB1v0GrS6MI4axf
|
AUTH_KEY=R9kX2HFA7ZjLdVYm8TsQWpCeNuB1v0GrS6MI4axf
|
||||||
|
STATEDIR=/tmp
|
||||||
1407
api/composer.lock
generated
Normal file
1407
api/composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"lxdapp.local": "testone"
|
"auftrag.local": "auftrag"
|
||||||
}
|
}
|
||||||
@ -6,14 +6,9 @@ use DI\ContainerBuilder;
|
|||||||
use Slim\Factory\AppFactory;
|
use Slim\Factory\AppFactory;
|
||||||
use Dotenv\Dotenv;
|
use Dotenv\Dotenv;
|
||||||
use App\Middleware\CorsMiddleware;
|
use App\Middleware\CorsMiddleware;
|
||||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
|
||||||
use Psr\Http\Message\ResponseInterface as Response;
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
use App\Controllers\CaptchaController;
|
use App\Controllers\CaptchaController;
|
||||||
use App\Controllers\LoginController;
|
use App\Controllers\LoginController;
|
||||||
use App\Controllers\HandoffController;
|
|
||||||
use App\Services\LxdService;
|
|
||||||
use Zounar\PHPProxy\Proxy;
|
|
||||||
use App\Utils\LogWriterHelper;
|
|
||||||
|
|
||||||
require __DIR__ . '/../vendor/autoload.php';
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
@ -25,7 +20,6 @@ $domain = $_ENV['MAIN_COOKIE_DOMAIN'] ?? '.lxdapp.local';
|
|||||||
session_set_cookie_params([
|
session_set_cookie_params([
|
||||||
'lifetime' => 0,
|
'lifetime' => 0,
|
||||||
'path' => '/',
|
'path' => '/',
|
||||||
'domain' => $domain,
|
|
||||||
'secure' => false, // set true if using HTTPS
|
'secure' => false, // set true if using HTTPS
|
||||||
'httponly' => true,
|
'httponly' => true,
|
||||||
'samesite' => 'Lax',
|
'samesite' => 'Lax',
|
||||||
@ -72,7 +66,6 @@ $app->group('/api', function ($group) {
|
|||||||
$group->get('/captcha', [CaptchaController::class, 'get']);
|
$group->get('/captcha', [CaptchaController::class, 'get']);
|
||||||
$group->post('/login', [LoginController::class, 'index']);
|
$group->post('/login', [LoginController::class, 'index']);
|
||||||
$group->get('/status', [LoginController::class, 'status']);
|
$group->get('/status', [LoginController::class, 'status']);
|
||||||
$group->get('/handoff/post', [HandoffController::class, 'post']);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,85 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Controllers;
|
|
||||||
|
|
||||||
use App\Services\LxdService;
|
|
||||||
use Psr\Http\Message\ResponseInterface;
|
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
|
||||||
|
|
||||||
class HandoffController
|
|
||||||
{
|
|
||||||
public function post(ServerRequestInterface $req, ResponseInterface $res): ResponseInterface
|
|
||||||
{
|
|
||||||
// if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
|
|
||||||
|
|
||||||
$q = $req->getQueryParams();
|
|
||||||
$name = (string)($q['name'] ?? '');
|
|
||||||
$id = (string)($q['handoff'] ?? '');
|
|
||||||
$path = (string)($q['path'] ?? '/login');
|
|
||||||
|
|
||||||
if (!$name || !$id) {
|
|
||||||
return $this->html($res, 400, '<h1>Bad request</h1>');
|
|
||||||
}
|
|
||||||
|
|
||||||
$lxd = new LxdService();
|
|
||||||
$ip = $lxd->getContainerIP($name);
|
|
||||||
if (!$ip) {
|
|
||||||
return $this->html($res, 503, '<h1>Container not ready</h1>');
|
|
||||||
}
|
|
||||||
|
|
||||||
$key = "handoff:$name:$id";
|
|
||||||
$data = $_SESSION[$key] ?? null;
|
|
||||||
unset($_SESSION[$key]); // one-time use
|
|
||||||
|
|
||||||
if (!$data || empty($data['username']) || empty($data['password'])) {
|
|
||||||
return $this->html($res, 410, '<h1>Handoff expired</h1>');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restrict to relative paths
|
|
||||||
$path = $this->sanitizePath($path);
|
|
||||||
|
|
||||||
// If your container has TLS, prefer https://
|
|
||||||
$action = 'http://' . $ip . $path;
|
|
||||||
|
|
||||||
$html = <<<HTML
|
|
||||||
<!doctype html>
|
|
||||||
<html>
|
|
||||||
<head><meta charset="utf-8"><title>Signing you in…</title></head>
|
|
||||||
<body>
|
|
||||||
<form id="f" method="POST" action="{$this->e($action)}">
|
|
||||||
<input type="hidden" name="username" value="{$this->e($data['username'])}">
|
|
||||||
<input type="hidden" name="password" value="{$this->e($data['password'])}">
|
|
||||||
</form>
|
|
||||||
<script>document.getElementById('f').submit();</script>
|
|
||||||
<noscript>
|
|
||||||
<p>JavaScript is required to continue. Click the button below.</p>
|
|
||||||
<button form="f" type="submit">Continue</button>
|
|
||||||
</noscript>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
HTML;
|
|
||||||
|
|
||||||
return $this->html($res, 200, $html);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function e(string $s): string
|
|
||||||
{
|
|
||||||
return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
private function html(ResponseInterface $res, int $code, string $html): ResponseInterface
|
|
||||||
{
|
|
||||||
$res->getBody()->write($html);
|
|
||||||
return $res->withHeader('Content-Type', 'text/html; charset=utf-8')->withStatus($code);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function sanitizePath(string $raw): string
|
|
||||||
{
|
|
||||||
if (preg_match('#^https?://#i', $raw)) return '/login';
|
|
||||||
if (!str_starts_with($raw, '/')) return '/login';
|
|
||||||
$path = parse_url($raw, PHP_URL_PATH) ?? '/login';
|
|
||||||
$allow = ['/', '/login', '/signin'];
|
|
||||||
return in_array($path, $allow, true) ? $path : '/login';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -7,6 +7,7 @@ use App\Services\LxdService;
|
|||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
use App\Utils\LogWriterHelper;
|
use App\Utils\LogWriterHelper;
|
||||||
|
use App\Utils\ContainerHelper;
|
||||||
|
|
||||||
class LoginController
|
class LoginController
|
||||||
{
|
{
|
||||||
@ -16,12 +17,7 @@ class LoginController
|
|||||||
public function index(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
|
public function index(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$origin = $request->getHeaderLine('Origin');
|
$name = ContainerHelper::getName($request);
|
||||||
$domain = !empty($origin) ? parse_url($origin, PHP_URL_HOST) : $request->getHeaderLine('Host');
|
|
||||||
|
|
||||||
$configPath = __DIR__ . '/../../config.json';
|
|
||||||
$config = file_exists($configPath) ? json_decode(file_get_contents($configPath), true) : [];
|
|
||||||
$name = $config[$domain] ?? null;
|
|
||||||
|
|
||||||
$params = (array)$request->getParsedBody();
|
$params = (array)$request->getParsedBody();
|
||||||
|
|
||||||
@ -43,30 +39,11 @@ class LoginController
|
|||||||
$lxd->startContainer($name);
|
$lxd->startContainer($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log path only (avoid leaking query in logs)
|
LogWriterHelper::write($name);
|
||||||
$uri = $request->getUri();
|
|
||||||
LogWriterHelper::write($name, $uri->getPath());
|
|
||||||
|
|
||||||
// ---- NEW: create one-time handoff and store creds server-side ----
|
|
||||||
$handoffId = bin2hex(random_bytes(16));
|
|
||||||
$_SESSION["handoff:$name:$handoffId"] = [
|
|
||||||
'username' => (string)($params['username'] ?? ''),
|
|
||||||
'password' => (string)($params['password'] ?? ''),
|
|
||||||
'created_at' => time(),
|
|
||||||
];
|
|
||||||
|
|
||||||
// sanitize the container path (not a full URL!)
|
|
||||||
$path = $this->sanitizeRedirectPath($params['redirect'] ?? '/login');
|
|
||||||
|
|
||||||
// Client goes to waiting page; when ready it will be sent to the bridge
|
|
||||||
$redirect = '/waiting?name=' . rawurlencode($name)
|
|
||||||
. '&handoff=' . rawurlencode($handoffId)
|
|
||||||
. '&path=' . rawurlencode($path);
|
|
||||||
|
|
||||||
return $this->json($response, [
|
return $this->json($response, [
|
||||||
'status' => 'success',
|
'status' => 'success',
|
||||||
'message' => 'Container started!',
|
'message' => 'Container gestartet!'
|
||||||
'redirect' => $redirect
|
|
||||||
]);
|
]);
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
return $this->json($response, [
|
return $this->json($response, [
|
||||||
@ -78,8 +55,7 @@ class LoginController
|
|||||||
|
|
||||||
public function status(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
|
public function status(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
|
||||||
{
|
{
|
||||||
$queryParams = $request->getQueryParams();
|
$name = ContainerHelper::getName($request);
|
||||||
$name = $queryParams['name'] ?? '';
|
|
||||||
|
|
||||||
if (empty($name)) {
|
if (empty($name)) {
|
||||||
return $this->json($response, [
|
return $this->json($response, [
|
||||||
@ -115,6 +91,7 @@ class LoginController
|
|||||||
return $this->json($response, [
|
return $this->json($response, [
|
||||||
'status' => 'ready',
|
'status' => 'ready',
|
||||||
'ip' => $ip,
|
'ip' => $ip,
|
||||||
|
'name' => $name,
|
||||||
'message' => 'Container is ready',
|
'message' => 'Container is ready',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -168,3 +145,4 @@ class LoginController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ use App\Services\LxdService;
|
|||||||
$lxdService = new LxdService();
|
$lxdService = new LxdService();
|
||||||
|
|
||||||
// Define the directory containing access logs
|
// Define the directory containing access logs
|
||||||
$logDir = realpath(__DIR__ . '/../../public/last-access-logs'); // Adjust if you're in /app/src/Cron or similar
|
$logDir = $_ENV['STATEDIR'] ?? "/var/www/html/lxd-app/api/public/last-access-logs";
|
||||||
|
|
||||||
// Define the idle threshold in minutes
|
// Define the idle threshold in minutes
|
||||||
$thresholdMinutes = 30;
|
$thresholdMinutes = 30;
|
||||||
@ -18,23 +18,15 @@ foreach (glob($logDir . '/*.txt') as $filePath) {
|
|||||||
// Extract the container name from the file name
|
// Extract the container name from the file name
|
||||||
$containerName = basename($filePath, '.txt');
|
$containerName = basename($filePath, '.txt');
|
||||||
|
|
||||||
// Get the last line from the log file
|
// Get the last modified time of the file
|
||||||
$lastLine = getLastLine($filePath);
|
$lastModified = filemtime($filePath);
|
||||||
if (!$lastLine) {
|
if (!$lastModified) {
|
||||||
echo "No access logs found for $containerName.\n";
|
echo "Failed to get modification time for $containerName.\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the timestamp from the last log entry
|
$now = time();
|
||||||
$parts = explode(' : ', $lastLine);
|
$interval = $now - $lastModified;
|
||||||
if (!isset($parts[0])) continue;
|
|
||||||
|
|
||||||
$lastAccess = DateTime::createFromFormat('Y-m-d H:i:s', trim($parts[0]));
|
|
||||||
if (!$lastAccess) continue;
|
|
||||||
|
|
||||||
// Calculate the idle time in seconds
|
|
||||||
$now = new DateTime();
|
|
||||||
$interval = $now->getTimestamp() - $lastAccess->getTimestamp();
|
|
||||||
|
|
||||||
// Check if the container has been idle for longer than the threshold
|
// Check if the container has been idle for longer than the threshold
|
||||||
if ($interval > $thresholdMinutes * 60) {
|
if ($interval > $thresholdMinutes * 60) {
|
||||||
@ -49,20 +41,7 @@ foreach (glob($logDir . '/*.txt') as $filePath) {
|
|||||||
echo "Container $containerName does not exist.\n";
|
echo "Container $containerName does not exist.\n";
|
||||||
}
|
}
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
// Handle any errors that occur while stopping the container
|
|
||||||
echo "Error stopping $containerName: " . $e->getMessage() . "\n";
|
echo "Error stopping $containerName: " . $e->getMessage() . "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the last non-empty line from a file.
|
|
||||||
*
|
|
||||||
* @param string $filePath Path to the file.
|
|
||||||
* @return string|null The last line, or null if the file is empty.
|
|
||||||
*/
|
|
||||||
function getLastLine(string $filePath): ?string
|
|
||||||
{
|
|
||||||
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
|
||||||
return $lines ? end($lines) : null;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -36,6 +36,7 @@ class LxdService
|
|||||||
curl_setopt($ch, CURLOPT_SSLCERT, $clientCert);
|
curl_setopt($ch, CURLOPT_SSLCERT, $clientCert);
|
||||||
curl_setopt($ch, CURLOPT_SSLKEY, $clientKey);
|
curl_setopt($ch, CURLOPT_SSLKEY, $clientKey);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||||
|
|
||||||
@ -84,6 +85,7 @@ class LxdService
|
|||||||
curl_setopt($ch, CURLOPT_SSLCERT, $clientCert);
|
curl_setopt($ch, CURLOPT_SSLCERT, $clientCert);
|
||||||
curl_setopt($ch, CURLOPT_SSLKEY, $clientKey);
|
curl_setopt($ch, CURLOPT_SSLKEY, $clientKey);
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
|
||||||
|
|
||||||
|
|||||||
33
api/src/Utils/ContainerHelper.php
Normal file
33
api/src/Utils/ContainerHelper.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Utils;
|
||||||
|
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Illuminate\Support\Facades\File;
|
||||||
|
|
||||||
|
class ContainerHelper
|
||||||
|
{
|
||||||
|
public static function getName(ServerRequestInterface $request): ?string
|
||||||
|
{
|
||||||
|
// Try to get Origin header, fallback to Host
|
||||||
|
$origin = $request->getHeaderLine('Origin');
|
||||||
|
$domain = !empty($origin) ? parse_url($origin, PHP_URL_HOST) : $request->getHeaderLine('Host');
|
||||||
|
|
||||||
|
// Load config.json once
|
||||||
|
$config = self::getConfig();
|
||||||
|
return $config[$domain] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getConfig(): array
|
||||||
|
{
|
||||||
|
static $config = null;
|
||||||
|
|
||||||
|
if ($config !== null) {
|
||||||
|
return $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
$configPath = __DIR__ . '/../../config.json';
|
||||||
|
|
||||||
|
return file_exists($configPath) ? json_decode(file_get_contents($configPath), true) : [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,19 +3,7 @@
|
|||||||
namespace App\Utils;
|
namespace App\Utils;
|
||||||
|
|
||||||
class LogWriterHelper {
|
class LogWriterHelper {
|
||||||
public static function write(string $name, string $uri): void {
|
public static function write(string $name): void {
|
||||||
// Dynamically resolve the log directory relative to the current file
|
touch($_ENV['STATEDIR']."/".$name);
|
||||||
$logDir = realpath(__DIR__ . '/../../public/last-access-logs');
|
|
||||||
|
|
||||||
// If the resolved path doesn't exist (e.g., public dir was missing), create it
|
|
||||||
if (!$logDir) {
|
|
||||||
$logDir = __DIR__ . '/../../public/last-access-logs';
|
|
||||||
if (!file_exists($logDir)) {
|
|
||||||
mkdir($logDir, 0777, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$logLine = date("Y-m-d H:i:s") . " : " . $uri . "\n";
|
|
||||||
file_put_contents($logDir . '/' . $name . '.txt', $logLine, FILE_APPEND);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
25
api/vendor/autoload.php
vendored
Normal file
25
api/vendor/autoload.php
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID < 50600) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, $err);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo $err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger_error(
|
||||||
|
$err,
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInit922ee7e3fd54ca2747cf5ce18d09b50c::getLoader();
|
||||||
579
api/vendor/composer/ClassLoader.php
vendored
Normal file
579
api/vendor/composer/ClassLoader.php
vendored
Normal file
@ -0,0 +1,579 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see https://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see https://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
/** @var \Closure(string):void */
|
||||||
|
private static $includeFile;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $vendorDir;
|
||||||
|
|
||||||
|
// PSR-4
|
||||||
|
/**
|
||||||
|
* @var array<string, array<string, int>>
|
||||||
|
*/
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var array<string, list<string>>
|
||||||
|
*/
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
/**
|
||||||
|
* List of PSR-0 prefixes
|
||||||
|
*
|
||||||
|
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||||
|
*
|
||||||
|
* @var array<string, array<string, list<string>>>
|
||||||
|
*/
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $useIncludePath = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
private $classMap = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, bool>
|
||||||
|
*/
|
||||||
|
private $missingClasses = array();
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, self>
|
||||||
|
*/
|
||||||
|
private static $registeredLoaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|null $vendorDir
|
||||||
|
*/
|
||||||
|
public function __construct($vendorDir = null)
|
||||||
|
{
|
||||||
|
$this->vendorDir = $vendorDir;
|
||||||
|
self::initializeIncludeClosure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string> Array of classname => path
|
||||||
|
*/
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, string> $classMap Class to filename map
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 base directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
|
||||||
|
if (null === $this->vendorDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prepend) {
|
||||||
|
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||||
|
} else {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
|
||||||
|
if (null !== $this->vendorDir) {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return true|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
$includeFile = self::$includeFile;
|
||||||
|
$includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||||
|
*
|
||||||
|
* @return array<string, self>
|
||||||
|
*/
|
||||||
|
public static function getRegisteredLoaders()
|
||||||
|
{
|
||||||
|
return self::$registeredLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
* @param string $ext
|
||||||
|
* @return string|false
|
||||||
|
*/
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath . '\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function initializeIncludeClosure()
|
||||||
|
{
|
||||||
|
if (self::$includeFile !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
self::$includeFile = \Closure::bind(static function($file) {
|
||||||
|
include $file;
|
||||||
|
}, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
359
api/vendor/composer/InstalledVersions.php
vendored
Normal file
359
api/vendor/composer/InstalledVersions.php
vendored
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer;
|
||||||
|
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
|
use Composer\Semver\VersionParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is copied in every Composer installed project and available to all
|
||||||
|
*
|
||||||
|
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||||
|
*
|
||||||
|
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||||
|
*
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class InstalledVersions
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var mixed[]|null
|
||||||
|
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||||
|
*/
|
||||||
|
private static $installed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool|null
|
||||||
|
*/
|
||||||
|
private static $canGetVendors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static $installedByVendor = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackages()
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
$packages[] = array_keys($installed['versions']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 === \count($packages)) {
|
||||||
|
return $packages[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names with a specific type e.g. 'library'
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackagesByType($type)
|
||||||
|
{
|
||||||
|
$packagesByType = array();
|
||||||
|
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
foreach ($installed['versions'] as $name => $package) {
|
||||||
|
if (isset($package['type']) && $package['type'] === $type) {
|
||||||
|
$packagesByType[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packagesByType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package is installed
|
||||||
|
*
|
||||||
|
* This also returns true if the package name is provided or replaced by another package
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @param bool $includeDevRequirements
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (isset($installed['versions'][$packageName])) {
|
||||||
|
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package satisfies a version constraint
|
||||||
|
*
|
||||||
|
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||||
|
*
|
||||||
|
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||||
|
*
|
||||||
|
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||||
|
* @param string $packageName
|
||||||
|
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||||
|
{
|
||||||
|
$constraint = $parser->parseConstraints((string) $constraint);
|
||||||
|
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||||
|
|
||||||
|
return $provided->matches($constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||||
|
*
|
||||||
|
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||||
|
* whether a given version of a package is installed, and not just whether it exists
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string Version constraint usable with composer/semver
|
||||||
|
*/
|
||||||
|
public static function getVersionRanges($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ranges = array();
|
||||||
|
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' || ', $ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getPrettyVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||||
|
*/
|
||||||
|
public static function getReference($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['reference'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||||
|
*/
|
||||||
|
public static function getInstallPath($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||||
|
*/
|
||||||
|
public static function getRootPackage()
|
||||||
|
{
|
||||||
|
$installed = self::getInstalled();
|
||||||
|
|
||||||
|
return $installed[0]['root'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw installed.php data for custom implementations
|
||||||
|
*
|
||||||
|
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||||
|
*/
|
||||||
|
public static function getRawData()
|
||||||
|
{
|
||||||
|
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
self::$installed = include __DIR__ . '/installed.php';
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||||
|
*
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
public static function getAllRawData()
|
||||||
|
{
|
||||||
|
return self::getInstalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lets you reload the static array from another file
|
||||||
|
*
|
||||||
|
* This is only useful for complex integrations in which a project needs to use
|
||||||
|
* this class but then also needs to execute another project's autoloader in process,
|
||||||
|
* and wants to ensure both projects have access to their version of installed.php.
|
||||||
|
*
|
||||||
|
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||||
|
* the data it needs from this class, then call reload() with
|
||||||
|
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||||
|
* the project in which it runs can then also use this class safely, without
|
||||||
|
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||||
|
*
|
||||||
|
* @param array[] $data A vendor/composer/installed.php data set
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||||
|
*/
|
||||||
|
public static function reload($data)
|
||||||
|
{
|
||||||
|
self::$installed = $data;
|
||||||
|
self::$installedByVendor = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static function getInstalled()
|
||||||
|
{
|
||||||
|
if (null === self::$canGetVendors) {
|
||||||
|
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed = array();
|
||||||
|
|
||||||
|
if (self::$canGetVendors) {
|
||||||
|
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||||
|
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir];
|
||||||
|
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||||
|
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||||
|
$required = require $vendorDir.'/composer/installed.php';
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir] = $required;
|
||||||
|
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||||
|
self::$installed = $installed[count($installed) - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||||
|
$required = require __DIR__ . '/installed.php';
|
||||||
|
self::$installed = $required;
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::$installed !== array()) {
|
||||||
|
$installed[] = self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
api/vendor/composer/LICENSE
vendored
Normal file
19
api/vendor/composer/LICENSE
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
15
api/vendor/composer/autoload_classmap.php
vendored
Normal file
15
api/vendor/composer/autoload_classmap.php
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||||
|
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||||
|
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
|
||||||
|
'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
|
||||||
|
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
|
||||||
|
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
|
||||||
|
);
|
||||||
15
api/vendor/composer/autoload_files.php
vendored
Normal file
15
api/vendor/composer/autoload_files.php
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_files.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
|
||||||
|
'253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
|
||||||
|
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
|
||||||
|
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
|
||||||
|
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||||
|
'b33e3d135e5d9e47d845c576147bda89' => $vendorDir . '/php-di/php-di/src/functions.php',
|
||||||
|
);
|
||||||
9
api/vendor/composer/autoload_namespaces.php
vendored
Normal file
9
api/vendor/composer/autoload_namespaces.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
);
|
||||||
28
api/vendor/composer/autoload_psr4.php
vendored
Normal file
28
api/vendor/composer/autoload_psr4.php
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Zounar\\PHPProxy\\' => array($vendorDir . '/zounar/php-proxy'),
|
||||||
|
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
|
||||||
|
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
||||||
|
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
|
||||||
|
'Slim\\Psr7\\' => array($vendorDir . '/slim/psr7/src'),
|
||||||
|
'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
|
||||||
|
'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
|
||||||
|
'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'),
|
||||||
|
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
|
||||||
|
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
|
||||||
|
'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'),
|
||||||
|
'Laravel\\SerializableClosure\\' => array($vendorDir . '/laravel/serializable-closure/src'),
|
||||||
|
'Invoker\\' => array($vendorDir . '/php-di/invoker/src'),
|
||||||
|
'GrahamCampbell\\ResultType\\' => array($vendorDir . '/graham-campbell/result-type/src'),
|
||||||
|
'Fig\\Http\\Message\\' => array($vendorDir . '/fig/http-message-util/src'),
|
||||||
|
'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'),
|
||||||
|
'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'),
|
||||||
|
'DI\\' => array($vendorDir . '/php-di/php-di/src'),
|
||||||
|
'App\\' => array($baseDir . '/src'),
|
||||||
|
);
|
||||||
50
api/vendor/composer/autoload_real.php
vendored
Normal file
50
api/vendor/composer/autoload_real.php
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
|
class ComposerAutoloaderInit922ee7e3fd54ca2747cf5ce18d09b50c
|
||||||
|
{
|
||||||
|
private static $loader;
|
||||||
|
|
||||||
|
public static function loadClassLoader($class)
|
||||||
|
{
|
||||||
|
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||||
|
require __DIR__ . '/ClassLoader.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Composer\Autoload\ClassLoader
|
||||||
|
*/
|
||||||
|
public static function getLoader()
|
||||||
|
{
|
||||||
|
if (null !== self::$loader) {
|
||||||
|
return self::$loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
require __DIR__ . '/platform_check.php';
|
||||||
|
|
||||||
|
spl_autoload_register(array('ComposerAutoloaderInit922ee7e3fd54ca2747cf5ce18d09b50c', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInit922ee7e3fd54ca2747cf5ce18d09b50c', 'loadClassLoader'));
|
||||||
|
|
||||||
|
require __DIR__ . '/autoload_static.php';
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c::getInitializer($loader));
|
||||||
|
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
$filesToLoad = \Composer\Autoload\ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c::$files;
|
||||||
|
$requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
|
||||||
|
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
||||||
|
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
|
||||||
|
|
||||||
|
require $file;
|
||||||
|
}
|
||||||
|
}, null, null);
|
||||||
|
foreach ($filesToLoad as $fileIdentifier => $file) {
|
||||||
|
$requireFile($fileIdentifier, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
}
|
||||||
|
}
|
||||||
166
api/vendor/composer/autoload_static.php
vendored
Normal file
166
api/vendor/composer/autoload_static.php
vendored
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c
|
||||||
|
{
|
||||||
|
public static $files = array (
|
||||||
|
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
|
||||||
|
'253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php',
|
||||||
|
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
|
||||||
|
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
|
||||||
|
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||||
|
'b33e3d135e5d9e47d845c576147bda89' => __DIR__ . '/..' . '/php-di/php-di/src/functions.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'Z' =>
|
||||||
|
array (
|
||||||
|
'Zounar\\PHPProxy\\' => 16,
|
||||||
|
),
|
||||||
|
'S' =>
|
||||||
|
array (
|
||||||
|
'Symfony\\Polyfill\\Php80\\' => 23,
|
||||||
|
'Symfony\\Polyfill\\Mbstring\\' => 26,
|
||||||
|
'Symfony\\Polyfill\\Ctype\\' => 23,
|
||||||
|
'Slim\\Psr7\\' => 10,
|
||||||
|
'Slim\\' => 5,
|
||||||
|
),
|
||||||
|
'P' =>
|
||||||
|
array (
|
||||||
|
'Psr\\Log\\' => 8,
|
||||||
|
'Psr\\Http\\Server\\' => 16,
|
||||||
|
'Psr\\Http\\Message\\' => 17,
|
||||||
|
'Psr\\Container\\' => 14,
|
||||||
|
'PhpOption\\' => 10,
|
||||||
|
),
|
||||||
|
'L' =>
|
||||||
|
array (
|
||||||
|
'Laravel\\SerializableClosure\\' => 28,
|
||||||
|
),
|
||||||
|
'I' =>
|
||||||
|
array (
|
||||||
|
'Invoker\\' => 8,
|
||||||
|
),
|
||||||
|
'G' =>
|
||||||
|
array (
|
||||||
|
'GrahamCampbell\\ResultType\\' => 26,
|
||||||
|
),
|
||||||
|
'F' =>
|
||||||
|
array (
|
||||||
|
'Fig\\Http\\Message\\' => 17,
|
||||||
|
'FastRoute\\' => 10,
|
||||||
|
),
|
||||||
|
'D' =>
|
||||||
|
array (
|
||||||
|
'Dotenv\\' => 7,
|
||||||
|
'DI\\' => 3,
|
||||||
|
),
|
||||||
|
'A' =>
|
||||||
|
array (
|
||||||
|
'App\\' => 4,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'Zounar\\PHPProxy\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/zounar/php-proxy',
|
||||||
|
),
|
||||||
|
'Symfony\\Polyfill\\Php80\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
|
||||||
|
),
|
||||||
|
'Symfony\\Polyfill\\Mbstring\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
|
||||||
|
),
|
||||||
|
'Symfony\\Polyfill\\Ctype\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
|
||||||
|
),
|
||||||
|
'Slim\\Psr7\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/slim/psr7/src',
|
||||||
|
),
|
||||||
|
'Slim\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/slim/slim/Slim',
|
||||||
|
),
|
||||||
|
'Psr\\Log\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/psr/log/src',
|
||||||
|
),
|
||||||
|
'Psr\\Http\\Server\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/psr/http-server-handler/src',
|
||||||
|
1 => __DIR__ . '/..' . '/psr/http-server-middleware/src',
|
||||||
|
),
|
||||||
|
'Psr\\Http\\Message\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/psr/http-message/src',
|
||||||
|
1 => __DIR__ . '/..' . '/psr/http-factory/src',
|
||||||
|
),
|
||||||
|
'Psr\\Container\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/psr/container/src',
|
||||||
|
),
|
||||||
|
'PhpOption\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/phpoption/phpoption/src/PhpOption',
|
||||||
|
),
|
||||||
|
'Laravel\\SerializableClosure\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/laravel/serializable-closure/src',
|
||||||
|
),
|
||||||
|
'Invoker\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/php-di/invoker/src',
|
||||||
|
),
|
||||||
|
'GrahamCampbell\\ResultType\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/graham-campbell/result-type/src',
|
||||||
|
),
|
||||||
|
'Fig\\Http\\Message\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/fig/http-message-util/src',
|
||||||
|
),
|
||||||
|
'FastRoute\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/nikic/fast-route/src',
|
||||||
|
),
|
||||||
|
'Dotenv\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/vlucas/phpdotenv/src',
|
||||||
|
),
|
||||||
|
'DI\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/php-di/php-di/src',
|
||||||
|
),
|
||||||
|
'App\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/../..' . '/src',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $classMap = array (
|
||||||
|
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||||
|
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||||
|
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
|
||||||
|
'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
|
||||||
|
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
|
||||||
|
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c::$prefixDirsPsr4;
|
||||||
|
$loader->classMap = ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c::$classMap;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
1457
api/vendor/composer/installed.json
vendored
Normal file
1457
api/vendor/composer/installed.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
230
api/vendor/composer/installed.php
vendored
Normal file
230
api/vendor/composer/installed.php
vendored
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
<?php return array(
|
||||||
|
'root' => array(
|
||||||
|
'name' => '__root__',
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => 'a3f5b5a0cf9cf2b9b6c979be8bbe2d440d15cd10',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev' => true,
|
||||||
|
),
|
||||||
|
'versions' => array(
|
||||||
|
'__root__' => array(
|
||||||
|
'pretty_version' => 'dev-main',
|
||||||
|
'version' => 'dev-main',
|
||||||
|
'reference' => 'a3f5b5a0cf9cf2b9b6c979be8bbe2d440d15cd10',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'fig/http-message-util' => array(
|
||||||
|
'pretty_version' => '1.1.5',
|
||||||
|
'version' => '1.1.5.0',
|
||||||
|
'reference' => '9d94dc0154230ac39e5bf89398b324a86f63f765',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../fig/http-message-util',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'graham-campbell/result-type' => array(
|
||||||
|
'pretty_version' => 'v1.1.3',
|
||||||
|
'version' => '1.1.3.0',
|
||||||
|
'reference' => '3ba905c11371512af9d9bdd27d99b782216b6945',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../graham-campbell/result-type',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'laravel/serializable-closure' => array(
|
||||||
|
'pretty_version' => 'v2.0.4',
|
||||||
|
'version' => '2.0.4.0',
|
||||||
|
'reference' => 'b352cf0534aa1ae6b4d825d1e762e35d43f8a841',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../laravel/serializable-closure',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'nikic/fast-route' => array(
|
||||||
|
'pretty_version' => 'v1.3.0',
|
||||||
|
'version' => '1.3.0.0',
|
||||||
|
'reference' => '181d480e08d9476e61381e04a71b34dc0432e812',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../nikic/fast-route',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'php-di/invoker' => array(
|
||||||
|
'pretty_version' => '2.3.7',
|
||||||
|
'version' => '2.3.7.0',
|
||||||
|
'reference' => '3c1ddfdef181431fbc4be83378f6d036d59e81e1',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../php-di/invoker',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'php-di/php-di' => array(
|
||||||
|
'pretty_version' => '7.1.1',
|
||||||
|
'version' => '7.1.1.0',
|
||||||
|
'reference' => 'f88054cc052e40dbe7b383c8817c19442d480352',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../php-di/php-di',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'phpoption/phpoption' => array(
|
||||||
|
'pretty_version' => '1.9.4',
|
||||||
|
'version' => '1.9.4.0',
|
||||||
|
'reference' => '638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../phpoption/phpoption',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/container' => array(
|
||||||
|
'pretty_version' => '2.0.2',
|
||||||
|
'version' => '2.0.2.0',
|
||||||
|
'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../psr/container',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/container-implementation' => array(
|
||||||
|
'dev_requirement' => false,
|
||||||
|
'provided' => array(
|
||||||
|
0 => '^1.0',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'psr/http-factory' => array(
|
||||||
|
'pretty_version' => '1.1.0',
|
||||||
|
'version' => '1.1.0.0',
|
||||||
|
'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../psr/http-factory',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/http-factory-implementation' => array(
|
||||||
|
'dev_requirement' => false,
|
||||||
|
'provided' => array(
|
||||||
|
0 => '^1.0',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'psr/http-message' => array(
|
||||||
|
'pretty_version' => '2.0',
|
||||||
|
'version' => '2.0.0.0',
|
||||||
|
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../psr/http-message',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/http-message-implementation' => array(
|
||||||
|
'dev_requirement' => false,
|
||||||
|
'provided' => array(
|
||||||
|
0 => '^1.0 || ^2.0',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'psr/http-server-handler' => array(
|
||||||
|
'pretty_version' => '1.0.2',
|
||||||
|
'version' => '1.0.2.0',
|
||||||
|
'reference' => '84c4fb66179be4caaf8e97bd239203245302e7d4',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../psr/http-server-handler',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/http-server-middleware' => array(
|
||||||
|
'pretty_version' => '1.0.2',
|
||||||
|
'version' => '1.0.2.0',
|
||||||
|
'reference' => 'c1481f747daaa6a0782775cd6a8c26a1bf4a3829',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../psr/http-server-middleware',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'psr/log' => array(
|
||||||
|
'pretty_version' => '3.0.2',
|
||||||
|
'version' => '3.0.2.0',
|
||||||
|
'reference' => 'f16e1d5863e37f8d8c2a01719f5b34baa2b714d3',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../psr/log',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'ralouphie/getallheaders' => array(
|
||||||
|
'pretty_version' => '3.0.3',
|
||||||
|
'version' => '3.0.3.0',
|
||||||
|
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../ralouphie/getallheaders',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'slim/psr7' => array(
|
||||||
|
'pretty_version' => '1.7.1',
|
||||||
|
'version' => '1.7.1.0',
|
||||||
|
'reference' => 'fe98653e7983010aa85c1d137c9b9ad5a1cd187d',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../slim/psr7',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'slim/slim' => array(
|
||||||
|
'pretty_version' => '4.15.0',
|
||||||
|
'version' => '4.15.0.0',
|
||||||
|
'reference' => '17eba5182975878a0ab9b27982cd2e2cfcb67ea2',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../slim/slim',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'symfony/polyfill-ctype' => array(
|
||||||
|
'pretty_version' => 'v1.33.0',
|
||||||
|
'version' => '1.33.0.0',
|
||||||
|
'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'symfony/polyfill-mbstring' => array(
|
||||||
|
'pretty_version' => 'v1.33.0',
|
||||||
|
'version' => '1.33.0.0',
|
||||||
|
'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'symfony/polyfill-php80' => array(
|
||||||
|
'pretty_version' => 'v1.33.0',
|
||||||
|
'version' => '1.33.0.0',
|
||||||
|
'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'vlucas/phpdotenv' => array(
|
||||||
|
'pretty_version' => 'v5.6.2',
|
||||||
|
'version' => '5.6.2.0',
|
||||||
|
'reference' => '24ac4c74f91ee2c193fa1aaa5c249cb0822809af',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../vlucas/phpdotenv',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'zounar/php-proxy' => array(
|
||||||
|
'pretty_version' => '1.1.0',
|
||||||
|
'version' => '1.1.0.0',
|
||||||
|
'reference' => '67e83a8bd7489b220a94402664fa22d9e21e3d40',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../zounar/php-proxy',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
26
api/vendor/composer/platform_check.php
vendored
Normal file
26
api/vendor/composer/platform_check.php
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// platform_check.php @generated by Composer
|
||||||
|
|
||||||
|
$issues = array();
|
||||||
|
|
||||||
|
if (!(PHP_VERSION_ID >= 80100)) {
|
||||||
|
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($issues) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trigger_error(
|
||||||
|
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||||
|
E_USER_ERROR
|
||||||
|
);
|
||||||
|
}
|
||||||
1
api/vendor/fig/http-message-util/.gitignore
vendored
Normal file
1
api/vendor/fig/http-message-util/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
vendor/
|
||||||
147
api/vendor/fig/http-message-util/CHANGELOG.md
vendored
Normal file
147
api/vendor/fig/http-message-util/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file, in reverse chronological order by release.
|
||||||
|
|
||||||
|
## 1.1.5 - 2020-11-24
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [#19](https://github.com/php-fig/http-message-util/pull/19) adds support for PHP 8.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
## 1.1.4 - 2020-02-05
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- [#15](https://github.com/php-fig/http-message-util/pull/15) removes the dependency on psr/http-message, as it is not technically necessary for usage of this package.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
## 1.1.3 - 2018-11-19
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [#10](https://github.com/php-fig/http-message-util/pull/10) adds the constants `StatusCodeInterface::STATUS_EARLY_HINTS` (103) and
|
||||||
|
`StatusCodeInterface::STATUS_TOO_EARLY` (425).
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
## 1.1.2 - 2017-02-09
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [#4](https://github.com/php-fig/http-message-util/pull/4) adds the constant
|
||||||
|
`StatusCodeInterface::STATUS_MISDIRECTED_REQUEST` (421).
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
## 1.1.1 - 2017-02-06
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [#3](https://github.com/php-fig/http-message-util/pull/3) adds the constant
|
||||||
|
`StatusCodeInterface::STATUS_IM_A_TEAPOT` (418).
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
## 1.1.0 - 2016-09-19
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- [#1](https://github.com/php-fig/http-message-util/pull/1) adds
|
||||||
|
`Fig\Http\Message\StatusCodeInterface`, with constants named after common
|
||||||
|
status reason phrases, with values indicating the status codes themselves.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
## 1.0.0 - 2017-08-05
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Adds `Fig\Http\Message\RequestMethodInterface`, with constants covering the
|
||||||
|
most common HTTP request methods as specified by the IETF.
|
||||||
|
|
||||||
|
### Deprecated
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Nothing.
|
||||||
19
api/vendor/fig/http-message-util/LICENSE
vendored
Normal file
19
api/vendor/fig/http-message-util/LICENSE
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2016 PHP Framework Interoperability Group
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
17
api/vendor/fig/http-message-util/README.md
vendored
Normal file
17
api/vendor/fig/http-message-util/README.md
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# PSR Http Message Util
|
||||||
|
|
||||||
|
This repository holds utility classes and constants to facilitate common
|
||||||
|
operations of [PSR-7](https://www.php-fig.org/psr/psr-7/); the primary purpose is
|
||||||
|
to provide constants for referring to request methods, response status codes and
|
||||||
|
messages, and potentially common headers.
|
||||||
|
|
||||||
|
Implementation of PSR-7 interfaces is **not** within the scope of this package.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Install by adding the package as a [Composer](https://getcomposer.org)
|
||||||
|
requirement:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ composer require fig/http-message-util
|
||||||
|
```
|
||||||
28
api/vendor/fig/http-message-util/composer.json
vendored
Normal file
28
api/vendor/fig/http-message-util/composer.json
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "fig/http-message-util",
|
||||||
|
"description": "Utility classes and constants for use with PSR-7 (psr/http-message)",
|
||||||
|
"keywords": ["psr", "psr-7", "http", "http-message", "request", "response"],
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "https://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "^5.3 || ^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"psr/http-message": "The package containing the PSR-7 interfaces"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Fig\\Http\\Message\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.1.x-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
api/vendor/fig/http-message-util/src/RequestMethodInterface.php
vendored
Normal file
34
api/vendor/fig/http-message-util/src/RequestMethodInterface.php
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fig\Http\Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines constants for common HTTP request methods.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* class RequestFactory implements RequestMethodInterface
|
||||||
|
* {
|
||||||
|
* public static function factory(
|
||||||
|
* $uri = '/',
|
||||||
|
* $method = self::METHOD_GET,
|
||||||
|
* $data = []
|
||||||
|
* ) {
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
interface RequestMethodInterface
|
||||||
|
{
|
||||||
|
const METHOD_HEAD = 'HEAD';
|
||||||
|
const METHOD_GET = 'GET';
|
||||||
|
const METHOD_POST = 'POST';
|
||||||
|
const METHOD_PUT = 'PUT';
|
||||||
|
const METHOD_PATCH = 'PATCH';
|
||||||
|
const METHOD_DELETE = 'DELETE';
|
||||||
|
const METHOD_PURGE = 'PURGE';
|
||||||
|
const METHOD_OPTIONS = 'OPTIONS';
|
||||||
|
const METHOD_TRACE = 'TRACE';
|
||||||
|
const METHOD_CONNECT = 'CONNECT';
|
||||||
|
}
|
||||||
107
api/vendor/fig/http-message-util/src/StatusCodeInterface.php
vendored
Normal file
107
api/vendor/fig/http-message-util/src/StatusCodeInterface.php
vendored
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fig\Http\Message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines constants for common HTTP status code.
|
||||||
|
*
|
||||||
|
* @see https://tools.ietf.org/html/rfc2295#section-8.1
|
||||||
|
* @see https://tools.ietf.org/html/rfc2324#section-2.3
|
||||||
|
* @see https://tools.ietf.org/html/rfc2518#section-9.7
|
||||||
|
* @see https://tools.ietf.org/html/rfc2774#section-7
|
||||||
|
* @see https://tools.ietf.org/html/rfc3229#section-10.4
|
||||||
|
* @see https://tools.ietf.org/html/rfc4918#section-11
|
||||||
|
* @see https://tools.ietf.org/html/rfc5842#section-7.1
|
||||||
|
* @see https://tools.ietf.org/html/rfc5842#section-7.2
|
||||||
|
* @see https://tools.ietf.org/html/rfc6585#section-3
|
||||||
|
* @see https://tools.ietf.org/html/rfc6585#section-4
|
||||||
|
* @see https://tools.ietf.org/html/rfc6585#section-5
|
||||||
|
* @see https://tools.ietf.org/html/rfc6585#section-6
|
||||||
|
* @see https://tools.ietf.org/html/rfc7231#section-6
|
||||||
|
* @see https://tools.ietf.org/html/rfc7238#section-3
|
||||||
|
* @see https://tools.ietf.org/html/rfc7725#section-3
|
||||||
|
* @see https://tools.ietf.org/html/rfc7540#section-9.1.2
|
||||||
|
* @see https://tools.ietf.org/html/rfc8297#section-2
|
||||||
|
* @see https://tools.ietf.org/html/rfc8470#section-7
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* <code>
|
||||||
|
* class ResponseFactory implements StatusCodeInterface
|
||||||
|
* {
|
||||||
|
* public function createResponse($code = self::STATUS_OK)
|
||||||
|
* {
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
interface StatusCodeInterface
|
||||||
|
{
|
||||||
|
// Informational 1xx
|
||||||
|
const STATUS_CONTINUE = 100;
|
||||||
|
const STATUS_SWITCHING_PROTOCOLS = 101;
|
||||||
|
const STATUS_PROCESSING = 102;
|
||||||
|
const STATUS_EARLY_HINTS = 103;
|
||||||
|
// Successful 2xx
|
||||||
|
const STATUS_OK = 200;
|
||||||
|
const STATUS_CREATED = 201;
|
||||||
|
const STATUS_ACCEPTED = 202;
|
||||||
|
const STATUS_NON_AUTHORITATIVE_INFORMATION = 203;
|
||||||
|
const STATUS_NO_CONTENT = 204;
|
||||||
|
const STATUS_RESET_CONTENT = 205;
|
||||||
|
const STATUS_PARTIAL_CONTENT = 206;
|
||||||
|
const STATUS_MULTI_STATUS = 207;
|
||||||
|
const STATUS_ALREADY_REPORTED = 208;
|
||||||
|
const STATUS_IM_USED = 226;
|
||||||
|
// Redirection 3xx
|
||||||
|
const STATUS_MULTIPLE_CHOICES = 300;
|
||||||
|
const STATUS_MOVED_PERMANENTLY = 301;
|
||||||
|
const STATUS_FOUND = 302;
|
||||||
|
const STATUS_SEE_OTHER = 303;
|
||||||
|
const STATUS_NOT_MODIFIED = 304;
|
||||||
|
const STATUS_USE_PROXY = 305;
|
||||||
|
const STATUS_RESERVED = 306;
|
||||||
|
const STATUS_TEMPORARY_REDIRECT = 307;
|
||||||
|
const STATUS_PERMANENT_REDIRECT = 308;
|
||||||
|
// Client Errors 4xx
|
||||||
|
const STATUS_BAD_REQUEST = 400;
|
||||||
|
const STATUS_UNAUTHORIZED = 401;
|
||||||
|
const STATUS_PAYMENT_REQUIRED = 402;
|
||||||
|
const STATUS_FORBIDDEN = 403;
|
||||||
|
const STATUS_NOT_FOUND = 404;
|
||||||
|
const STATUS_METHOD_NOT_ALLOWED = 405;
|
||||||
|
const STATUS_NOT_ACCEPTABLE = 406;
|
||||||
|
const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407;
|
||||||
|
const STATUS_REQUEST_TIMEOUT = 408;
|
||||||
|
const STATUS_CONFLICT = 409;
|
||||||
|
const STATUS_GONE = 410;
|
||||||
|
const STATUS_LENGTH_REQUIRED = 411;
|
||||||
|
const STATUS_PRECONDITION_FAILED = 412;
|
||||||
|
const STATUS_PAYLOAD_TOO_LARGE = 413;
|
||||||
|
const STATUS_URI_TOO_LONG = 414;
|
||||||
|
const STATUS_UNSUPPORTED_MEDIA_TYPE = 415;
|
||||||
|
const STATUS_RANGE_NOT_SATISFIABLE = 416;
|
||||||
|
const STATUS_EXPECTATION_FAILED = 417;
|
||||||
|
const STATUS_IM_A_TEAPOT = 418;
|
||||||
|
const STATUS_MISDIRECTED_REQUEST = 421;
|
||||||
|
const STATUS_UNPROCESSABLE_ENTITY = 422;
|
||||||
|
const STATUS_LOCKED = 423;
|
||||||
|
const STATUS_FAILED_DEPENDENCY = 424;
|
||||||
|
const STATUS_TOO_EARLY = 425;
|
||||||
|
const STATUS_UPGRADE_REQUIRED = 426;
|
||||||
|
const STATUS_PRECONDITION_REQUIRED = 428;
|
||||||
|
const STATUS_TOO_MANY_REQUESTS = 429;
|
||||||
|
const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
|
||||||
|
const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
|
||||||
|
// Server Errors 5xx
|
||||||
|
const STATUS_INTERNAL_SERVER_ERROR = 500;
|
||||||
|
const STATUS_NOT_IMPLEMENTED = 501;
|
||||||
|
const STATUS_BAD_GATEWAY = 502;
|
||||||
|
const STATUS_SERVICE_UNAVAILABLE = 503;
|
||||||
|
const STATUS_GATEWAY_TIMEOUT = 504;
|
||||||
|
const STATUS_VERSION_NOT_SUPPORTED = 505;
|
||||||
|
const STATUS_VARIANT_ALSO_NEGOTIATES = 506;
|
||||||
|
const STATUS_INSUFFICIENT_STORAGE = 507;
|
||||||
|
const STATUS_LOOP_DETECTED = 508;
|
||||||
|
const STATUS_NOT_EXTENDED = 510;
|
||||||
|
const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511;
|
||||||
|
}
|
||||||
21
api/vendor/graham-campbell/result-type/LICENSE
vendored
Normal file
21
api/vendor/graham-campbell/result-type/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2020-2024 Graham Campbell <hello@gjcampbell.co.uk>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
33
api/vendor/graham-campbell/result-type/composer.json
vendored
Normal file
33
api/vendor/graham-campbell/result-type/composer.json
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "graham-campbell/result-type",
|
||||||
|
"description": "An Implementation Of The Result Type",
|
||||||
|
"keywords": ["result", "result-type", "Result", "Result Type", "Result-Type", "Graham Campbell", "GrahamCampbell"],
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Graham Campbell",
|
||||||
|
"email": "hello@gjcampbell.co.uk",
|
||||||
|
"homepage": "https://github.com/GrahamCampbell"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5 || ^8.0",
|
||||||
|
"phpoption/phpoption": "^1.9.3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"GrahamCampbell\\ResultType\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"GrahamCampbell\\Tests\\ResultType\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"preferred-install": "dist"
|
||||||
|
}
|
||||||
|
}
|
||||||
121
api/vendor/graham-campbell/result-type/src/Error.php
vendored
Normal file
121
api/vendor/graham-campbell/result-type/src/Error.php
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Result Type.
|
||||||
|
*
|
||||||
|
* (c) Graham Campbell <hello@gjcampbell.co.uk>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace GrahamCampbell\ResultType;
|
||||||
|
|
||||||
|
use PhpOption\None;
|
||||||
|
use PhpOption\Some;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @template T
|
||||||
|
* @template E
|
||||||
|
*
|
||||||
|
* @extends \GrahamCampbell\ResultType\Result<T,E>
|
||||||
|
*/
|
||||||
|
final class Error extends Result
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var E
|
||||||
|
*/
|
||||||
|
private $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal constructor for an error value.
|
||||||
|
*
|
||||||
|
* @param E $value
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function __construct($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new error value.
|
||||||
|
*
|
||||||
|
* @template F
|
||||||
|
*
|
||||||
|
* @param F $value
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<T,F>
|
||||||
|
*/
|
||||||
|
public static function create($value)
|
||||||
|
{
|
||||||
|
return new self($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the success option value.
|
||||||
|
*
|
||||||
|
* @return \PhpOption\Option<T>
|
||||||
|
*/
|
||||||
|
public function success()
|
||||||
|
{
|
||||||
|
return None::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map over the success value.
|
||||||
|
*
|
||||||
|
* @template S
|
||||||
|
*
|
||||||
|
* @param callable(T):S $f
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<S,E>
|
||||||
|
*/
|
||||||
|
public function map(callable $f)
|
||||||
|
{
|
||||||
|
return self::create($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flat map over the success value.
|
||||||
|
*
|
||||||
|
* @template S
|
||||||
|
* @template F
|
||||||
|
*
|
||||||
|
* @param callable(T):\GrahamCampbell\ResultType\Result<S,F> $f
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<S,F>
|
||||||
|
*/
|
||||||
|
public function flatMap(callable $f)
|
||||||
|
{
|
||||||
|
/** @var \GrahamCampbell\ResultType\Result<S,F> */
|
||||||
|
return self::create($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the error option value.
|
||||||
|
*
|
||||||
|
* @return \PhpOption\Option<E>
|
||||||
|
*/
|
||||||
|
public function error()
|
||||||
|
{
|
||||||
|
return Some::create($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map over the error value.
|
||||||
|
*
|
||||||
|
* @template F
|
||||||
|
*
|
||||||
|
* @param callable(E):F $f
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<T,F>
|
||||||
|
*/
|
||||||
|
public function mapError(callable $f)
|
||||||
|
{
|
||||||
|
return self::create($f($this->value));
|
||||||
|
}
|
||||||
|
}
|
||||||
69
api/vendor/graham-campbell/result-type/src/Result.php
vendored
Normal file
69
api/vendor/graham-campbell/result-type/src/Result.php
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Result Type.
|
||||||
|
*
|
||||||
|
* (c) Graham Campbell <hello@gjcampbell.co.uk>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace GrahamCampbell\ResultType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @template T
|
||||||
|
* @template E
|
||||||
|
*/
|
||||||
|
abstract class Result
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the success option value.
|
||||||
|
*
|
||||||
|
* @return \PhpOption\Option<T>
|
||||||
|
*/
|
||||||
|
abstract public function success();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map over the success value.
|
||||||
|
*
|
||||||
|
* @template S
|
||||||
|
*
|
||||||
|
* @param callable(T):S $f
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<S,E>
|
||||||
|
*/
|
||||||
|
abstract public function map(callable $f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flat map over the success value.
|
||||||
|
*
|
||||||
|
* @template S
|
||||||
|
* @template F
|
||||||
|
*
|
||||||
|
* @param callable(T):\GrahamCampbell\ResultType\Result<S,F> $f
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<S,F>
|
||||||
|
*/
|
||||||
|
abstract public function flatMap(callable $f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the error option value.
|
||||||
|
*
|
||||||
|
* @return \PhpOption\Option<E>
|
||||||
|
*/
|
||||||
|
abstract public function error();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map over the error value.
|
||||||
|
*
|
||||||
|
* @template F
|
||||||
|
*
|
||||||
|
* @param callable(E):F $f
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<T,F>
|
||||||
|
*/
|
||||||
|
abstract public function mapError(callable $f);
|
||||||
|
}
|
||||||
120
api/vendor/graham-campbell/result-type/src/Success.php
vendored
Normal file
120
api/vendor/graham-campbell/result-type/src/Success.php
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Result Type.
|
||||||
|
*
|
||||||
|
* (c) Graham Campbell <hello@gjcampbell.co.uk>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace GrahamCampbell\ResultType;
|
||||||
|
|
||||||
|
use PhpOption\None;
|
||||||
|
use PhpOption\Some;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @template T
|
||||||
|
* @template E
|
||||||
|
*
|
||||||
|
* @extends \GrahamCampbell\ResultType\Result<T,E>
|
||||||
|
*/
|
||||||
|
final class Success extends Result
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var T
|
||||||
|
*/
|
||||||
|
private $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal constructor for a success value.
|
||||||
|
*
|
||||||
|
* @param T $value
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function __construct($value)
|
||||||
|
{
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new error value.
|
||||||
|
*
|
||||||
|
* @template S
|
||||||
|
*
|
||||||
|
* @param S $value
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<S,E>
|
||||||
|
*/
|
||||||
|
public static function create($value)
|
||||||
|
{
|
||||||
|
return new self($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the success option value.
|
||||||
|
*
|
||||||
|
* @return \PhpOption\Option<T>
|
||||||
|
*/
|
||||||
|
public function success()
|
||||||
|
{
|
||||||
|
return Some::create($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map over the success value.
|
||||||
|
*
|
||||||
|
* @template S
|
||||||
|
*
|
||||||
|
* @param callable(T):S $f
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<S,E>
|
||||||
|
*/
|
||||||
|
public function map(callable $f)
|
||||||
|
{
|
||||||
|
return self::create($f($this->value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flat map over the success value.
|
||||||
|
*
|
||||||
|
* @template S
|
||||||
|
* @template F
|
||||||
|
*
|
||||||
|
* @param callable(T):\GrahamCampbell\ResultType\Result<S,F> $f
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<S,F>
|
||||||
|
*/
|
||||||
|
public function flatMap(callable $f)
|
||||||
|
{
|
||||||
|
return $f($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the error option value.
|
||||||
|
*
|
||||||
|
* @return \PhpOption\Option<E>
|
||||||
|
*/
|
||||||
|
public function error()
|
||||||
|
{
|
||||||
|
return None::create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map over the error value.
|
||||||
|
*
|
||||||
|
* @template F
|
||||||
|
*
|
||||||
|
* @param callable(E):F $f
|
||||||
|
*
|
||||||
|
* @return \GrahamCampbell\ResultType\Result<T,F>
|
||||||
|
*/
|
||||||
|
public function mapError(callable $f)
|
||||||
|
{
|
||||||
|
return self::create($this->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
api/vendor/laravel/serializable-closure/LICENSE.md
vendored
Normal file
21
api/vendor/laravel/serializable-closure/LICENSE.md
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) Taylor Otwell
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
73
api/vendor/laravel/serializable-closure/README.md
vendored
Normal file
73
api/vendor/laravel/serializable-closure/README.md
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Serializable Closure
|
||||||
|
|
||||||
|
<a href="https://github.com/laravel/serializable-closure/actions">
|
||||||
|
<img src="https://github.com/laravel/serializable-closure/workflows/tests/badge.svg" alt="Build Status">
|
||||||
|
</a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/serializable-closure">
|
||||||
|
<img src="https://img.shields.io/packagist/dt/laravel/serializable-closure" alt="Total Downloads">
|
||||||
|
</a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/serializable-closure">
|
||||||
|
<img src="https://img.shields.io/packagist/v/laravel/serializable-closure" alt="Latest Stable Version">
|
||||||
|
</a>
|
||||||
|
<a href="https://packagist.org/packages/laravel/serializable-closure">
|
||||||
|
<img src="https://img.shields.io/packagist/l/laravel/serializable-closure" alt="License">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
> This project is a fork of the excellent [opis/closure: 3.x](https://github.com/opis/closure) package. At Laravel, we decided to fork this package as the upcoming version [4.x](https://github.com/opis/closure) is a complete rewrite on top of the [FFI extension](https://www.php.net/manual/en/book.ffi.php). As Laravel is a web framework, and FFI is not enabled by default in web requests, this fork allows us to keep using the `3.x` series while adding support for new PHP versions.
|
||||||
|
|
||||||
|
Laravel Serializable Closure provides an easy and secure way to **serialize closures in PHP**.
|
||||||
|
|
||||||
|
## Official Documentation
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
> **Requires [PHP 7.4+](https://php.net/releases/)**
|
||||||
|
|
||||||
|
First, install Laravel Serializable Closure via the [Composer](https://getcomposer.org/) package manager:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require laravel/serializable-closure
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
You may serialize a closure this way:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Laravel\SerializableClosure\SerializableClosure;
|
||||||
|
|
||||||
|
$closure = fn () => 'james';
|
||||||
|
|
||||||
|
// Recommended
|
||||||
|
SerializableClosure::setSecretKey('secret');
|
||||||
|
|
||||||
|
$serialized = serialize(new SerializableClosure($closure));
|
||||||
|
$closure = unserialize($serialized)->getClosure();
|
||||||
|
|
||||||
|
echo $closure(); // james;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Caveats
|
||||||
|
|
||||||
|
* Anonymous classes cannot be created within closures.
|
||||||
|
* Attributes cannot be used within closures.
|
||||||
|
* Serializing closures on REPL environments like Laravel Tinker is not supported.
|
||||||
|
* Serializing closures that reference objects with readonly properties is not supported.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Thank you for considering contributing to Serializable Closure! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||||
|
|
||||||
|
## Security Vulnerabilities
|
||||||
|
|
||||||
|
Please review [our security policy](https://github.com/laravel/serializable-closure/security/policy) on how to report security vulnerabilities.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Serializable Closure is open-sourced software licensed under the [MIT license](LICENSE.md).
|
||||||
53
api/vendor/laravel/serializable-closure/composer.json
vendored
Normal file
53
api/vendor/laravel/serializable-closure/composer.json
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"name": "laravel/serializable-closure",
|
||||||
|
"description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.",
|
||||||
|
"keywords": ["laravel", "Serializable", "closure"],
|
||||||
|
"license": "MIT",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/laravel/serializable-closure/issues",
|
||||||
|
"source": "https://github.com/laravel/serializable-closure"
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Taylor Otwell",
|
||||||
|
"email": "taylor@laravel.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nuno Maduro",
|
||||||
|
"email": "nuno@laravel.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"illuminate/support": "^10.0|^11.0|^12.0",
|
||||||
|
"nesbot/carbon": "^2.67|^3.0",
|
||||||
|
"pestphp/pest": "^2.36|^3.0",
|
||||||
|
"phpstan/phpstan": "^2.0",
|
||||||
|
"symfony/var-dumper": "^6.2.0|^7.0.0"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Laravel\\SerializableClosure\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"sort-packages": true,
|
||||||
|
"allow-plugins": {
|
||||||
|
"pestphp/pest-plugin": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minimum-stability": "dev",
|
||||||
|
"prefer-stable": true
|
||||||
|
}
|
||||||
20
api/vendor/laravel/serializable-closure/src/Contracts/Serializable.php
vendored
Normal file
20
api/vendor/laravel/serializable-closure/src/Contracts/Serializable.php
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Contracts;
|
||||||
|
|
||||||
|
interface Serializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Resolve the closure with the given arguments.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __invoke();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the closure that got serialized/unserialized.
|
||||||
|
*
|
||||||
|
* @return \Closure
|
||||||
|
*/
|
||||||
|
public function getClosure();
|
||||||
|
}
|
||||||
22
api/vendor/laravel/serializable-closure/src/Contracts/Signer.php
vendored
Normal file
22
api/vendor/laravel/serializable-closure/src/Contracts/Signer.php
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Contracts;
|
||||||
|
|
||||||
|
interface Signer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Sign the given serializable.
|
||||||
|
*
|
||||||
|
* @param string $serializable
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function sign($serializable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the given signature.
|
||||||
|
*
|
||||||
|
* @param array $signature
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function verify($signature);
|
||||||
|
}
|
||||||
19
api/vendor/laravel/serializable-closure/src/Exceptions/InvalidSignatureException.php
vendored
Normal file
19
api/vendor/laravel/serializable-closure/src/Exceptions/InvalidSignatureException.php
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class InvalidSignatureException extends Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new exception instance.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($message = 'Your serialized closure might have been modified or it\'s unsafe to be unserialized.')
|
||||||
|
{
|
||||||
|
parent::__construct($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
api/vendor/laravel/serializable-closure/src/Exceptions/MissingSecretKeyException.php
vendored
Normal file
19
api/vendor/laravel/serializable-closure/src/Exceptions/MissingSecretKeyException.php
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class MissingSecretKeyException extends Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new exception instance.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($message = 'No serializable closure secret key has been specified.')
|
||||||
|
{
|
||||||
|
parent::__construct($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
19
api/vendor/laravel/serializable-closure/src/Exceptions/PhpVersionNotSupportedException.php
vendored
Normal file
19
api/vendor/laravel/serializable-closure/src/Exceptions/PhpVersionNotSupportedException.php
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class PhpVersionNotSupportedException extends Exception
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create a new exception instance.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($message = 'PHP 7.3 is not supported.')
|
||||||
|
{
|
||||||
|
parent::__construct($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
126
api/vendor/laravel/serializable-closure/src/SerializableClosure.php
vendored
Normal file
126
api/vendor/laravel/serializable-closure/src/SerializableClosure.php
vendored
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Laravel\SerializableClosure\Exceptions\InvalidSignatureException;
|
||||||
|
use Laravel\SerializableClosure\Serializers\Signed;
|
||||||
|
use Laravel\SerializableClosure\Signers\Hmac;
|
||||||
|
|
||||||
|
class SerializableClosure
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The closure's serializable.
|
||||||
|
*
|
||||||
|
* @var \Laravel\SerializableClosure\Contracts\Serializable
|
||||||
|
*/
|
||||||
|
protected $serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new serializable closure instance.
|
||||||
|
*
|
||||||
|
* @param \Closure $closure
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Closure $closure)
|
||||||
|
{
|
||||||
|
$this->serializable = Serializers\Signed::$signer
|
||||||
|
? new Serializers\Signed($closure)
|
||||||
|
: new Serializers\Native($closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the closure with the given arguments.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __invoke()
|
||||||
|
{
|
||||||
|
return call_user_func_array($this->serializable, func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the closure.
|
||||||
|
*
|
||||||
|
* @return \Closure
|
||||||
|
*/
|
||||||
|
public function getClosure()
|
||||||
|
{
|
||||||
|
return $this->serializable->getClosure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new unsigned serializable closure instance.
|
||||||
|
*
|
||||||
|
* @param Closure $closure
|
||||||
|
* @return \Laravel\SerializableClosure\UnsignedSerializableClosure
|
||||||
|
*/
|
||||||
|
public static function unsigned(Closure $closure)
|
||||||
|
{
|
||||||
|
return new UnsignedSerializableClosure($closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the serializable closure secret key.
|
||||||
|
*
|
||||||
|
* @param string|null $secret
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function setSecretKey($secret)
|
||||||
|
{
|
||||||
|
Serializers\Signed::$signer = $secret
|
||||||
|
? new Hmac($secret)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the serializable closure secret key.
|
||||||
|
*
|
||||||
|
* @param \Closure|null $transformer
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function transformUseVariablesUsing($transformer)
|
||||||
|
{
|
||||||
|
Serializers\Native::$transformUseVariables = $transformer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the serializable closure secret key.
|
||||||
|
*
|
||||||
|
* @param \Closure|null $resolver
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function resolveUseVariablesUsing($resolver)
|
||||||
|
{
|
||||||
|
Serializers\Native::$resolveUseVariables = $resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the serializable representation of the closure.
|
||||||
|
*
|
||||||
|
* @return array{serializable: \Laravel\SerializableClosure\Serializers\Signed|\Laravel\SerializableClosure\Contracts\Serializable}
|
||||||
|
*/
|
||||||
|
public function __serialize()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'serializable' => $this->serializable,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the closure after serialization.
|
||||||
|
*
|
||||||
|
* @param array{serializable: \Laravel\SerializableClosure\Serializers\Signed|\Laravel\SerializableClosure\Contracts\Serializable} $data
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException
|
||||||
|
*/
|
||||||
|
public function __unserialize($data)
|
||||||
|
{
|
||||||
|
if (Signed::$signer && ! $data['serializable'] instanceof Signed) {
|
||||||
|
throw new InvalidSignatureException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->serializable = $data['serializable'];
|
||||||
|
}
|
||||||
|
}
|
||||||
526
api/vendor/laravel/serializable-closure/src/Serializers/Native.php
vendored
Normal file
526
api/vendor/laravel/serializable-closure/src/Serializers/Native.php
vendored
Normal file
@ -0,0 +1,526 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Serializers;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use DateTimeInterface;
|
||||||
|
use Laravel\SerializableClosure\Contracts\Serializable;
|
||||||
|
use Laravel\SerializableClosure\SerializableClosure;
|
||||||
|
use Laravel\SerializableClosure\Support\ClosureScope;
|
||||||
|
use Laravel\SerializableClosure\Support\ClosureStream;
|
||||||
|
use Laravel\SerializableClosure\Support\ReflectionClosure;
|
||||||
|
use Laravel\SerializableClosure\Support\SelfReference;
|
||||||
|
use Laravel\SerializableClosure\UnsignedSerializableClosure;
|
||||||
|
use ReflectionObject;
|
||||||
|
use ReflectionProperty;
|
||||||
|
use UnitEnum;
|
||||||
|
|
||||||
|
class Native implements Serializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Transform the use variables before serialization.
|
||||||
|
*
|
||||||
|
* @var \Closure|null
|
||||||
|
*/
|
||||||
|
public static $transformUseVariables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the use variables after unserialization.
|
||||||
|
*
|
||||||
|
* @var \Closure|null
|
||||||
|
*/
|
||||||
|
public static $resolveUseVariables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The closure to be serialized/unserialized.
|
||||||
|
*
|
||||||
|
* @var \Closure
|
||||||
|
*/
|
||||||
|
protected $closure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The closure's reflection.
|
||||||
|
*
|
||||||
|
* @var \Laravel\SerializableClosure\Support\ReflectionClosure|null
|
||||||
|
*/
|
||||||
|
protected $reflector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The closure's code.
|
||||||
|
*
|
||||||
|
* @var array|null
|
||||||
|
*/
|
||||||
|
protected $code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The closure's reference.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $reference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The closure's scope.
|
||||||
|
*
|
||||||
|
* @var \Laravel\SerializableClosure\Support\ClosureScope|null
|
||||||
|
*/
|
||||||
|
protected $scope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "key" that marks an array as recursive.
|
||||||
|
*/
|
||||||
|
const ARRAY_RECURSIVE_KEY = 'LARAVEL_SERIALIZABLE_RECURSIVE_KEY';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new serializable closure instance.
|
||||||
|
*
|
||||||
|
* @param \Closure $closure
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Closure $closure)
|
||||||
|
{
|
||||||
|
$this->closure = $closure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the closure with the given arguments.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __invoke()
|
||||||
|
{
|
||||||
|
return call_user_func_array($this->closure, func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the closure.
|
||||||
|
*
|
||||||
|
* @return \Closure
|
||||||
|
*/
|
||||||
|
public function getClosure()
|
||||||
|
{
|
||||||
|
return $this->closure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the serializable representation of the closure.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function __serialize()
|
||||||
|
{
|
||||||
|
if ($this->scope === null) {
|
||||||
|
$this->scope = new ClosureScope();
|
||||||
|
$this->scope->toSerialize++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->scope->serializations++;
|
||||||
|
|
||||||
|
$scope = $object = null;
|
||||||
|
$reflector = $this->getReflector();
|
||||||
|
|
||||||
|
if ($reflector->isBindingRequired()) {
|
||||||
|
$object = $reflector->getClosureThis();
|
||||||
|
|
||||||
|
static::wrapClosures($object, $this->scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($scope = $reflector->getClosureScopeClass()) {
|
||||||
|
$scope = $scope->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->reference = spl_object_hash($this->closure);
|
||||||
|
|
||||||
|
$this->scope[$this->closure] = $this;
|
||||||
|
|
||||||
|
$use = $reflector->getUseVariables();
|
||||||
|
|
||||||
|
if (static::$transformUseVariables) {
|
||||||
|
$use = call_user_func(static::$transformUseVariables, $reflector->getUseVariables());
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = $reflector->getCode();
|
||||||
|
|
||||||
|
$this->mapByReference($use);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'use' => $use,
|
||||||
|
'function' => $code,
|
||||||
|
'scope' => $scope,
|
||||||
|
'this' => $object,
|
||||||
|
'self' => $this->reference,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (! --$this->scope->serializations && ! --$this->scope->toSerialize) {
|
||||||
|
$this->scope = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the closure after serialization.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __unserialize($data)
|
||||||
|
{
|
||||||
|
ClosureStream::register();
|
||||||
|
|
||||||
|
$this->code = $data;
|
||||||
|
unset($data);
|
||||||
|
|
||||||
|
$this->code['objects'] = [];
|
||||||
|
|
||||||
|
if ($this->code['use']) {
|
||||||
|
$this->scope = new ClosureScope();
|
||||||
|
|
||||||
|
if (static::$resolveUseVariables) {
|
||||||
|
$this->code['use'] = call_user_func(static::$resolveUseVariables, $this->code['use']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->mapPointers($this->code['use']);
|
||||||
|
|
||||||
|
extract($this->code['use'], EXTR_OVERWRITE | EXTR_REFS);
|
||||||
|
|
||||||
|
$this->scope = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->closure = include ClosureStream::STREAM_PROTO.'://'.$this->code['function'];
|
||||||
|
|
||||||
|
if ($this->code['this'] === $this) {
|
||||||
|
$this->code['this'] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->closure = $this->closure->bindTo($this->code['this'], $this->code['scope']);
|
||||||
|
|
||||||
|
if (! empty($this->code['objects'])) {
|
||||||
|
foreach ($this->code['objects'] as $item) {
|
||||||
|
$item['property']->setValue($item['instance'], $item['object']->getClosure());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->code = $this->code['function'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the given closures are serializable.
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
* @param \Laravel\SerializableClosure\Support\ClosureScope $storage
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function wrapClosures(&$data, $storage)
|
||||||
|
{
|
||||||
|
if ($data instanceof Closure) {
|
||||||
|
$data = new static($data);
|
||||||
|
} elseif (is_array($data)) {
|
||||||
|
if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[self::ARRAY_RECURSIVE_KEY] = true;
|
||||||
|
|
||||||
|
foreach ($data as $key => &$value) {
|
||||||
|
if ($key === self::ARRAY_RECURSIVE_KEY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
static::wrapClosures($value, $storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($value);
|
||||||
|
unset($data[self::ARRAY_RECURSIVE_KEY]);
|
||||||
|
} elseif ($data instanceof \stdClass) {
|
||||||
|
if (isset($storage[$data])) {
|
||||||
|
$data = $storage[$data];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $storage[$data] = clone $data;
|
||||||
|
|
||||||
|
foreach ($data as &$value) {
|
||||||
|
static::wrapClosures($value, $storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($value);
|
||||||
|
} elseif (is_object($data) && ! $data instanceof static && ! $data instanceof UnitEnum) {
|
||||||
|
if (isset($storage[$data])) {
|
||||||
|
$data = $storage[$data];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$instance = $data;
|
||||||
|
$reflection = new ReflectionObject($instance);
|
||||||
|
|
||||||
|
if (! $reflection->isUserDefined()) {
|
||||||
|
$storage[$instance] = $data;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$storage[$instance] = $data = $reflection->newInstanceWithoutConstructor();
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (! $reflection->isUserDefined()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($reflection->getProperties() as $property) {
|
||||||
|
if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$property->setAccessible(true);
|
||||||
|
|
||||||
|
if (! $property->isInitialized($instance)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $property->getValue($instance);
|
||||||
|
|
||||||
|
if (is_array($value) || is_object($value)) {
|
||||||
|
static::wrapClosures($value, $storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
$property->setValue($data, $value);
|
||||||
|
}
|
||||||
|
} while ($reflection = $reflection->getParentClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the closure's reflector.
|
||||||
|
*
|
||||||
|
* @return \Laravel\SerializableClosure\Support\ReflectionClosure
|
||||||
|
*/
|
||||||
|
public function getReflector()
|
||||||
|
{
|
||||||
|
if ($this->reflector === null) {
|
||||||
|
$this->code = null;
|
||||||
|
$this->reflector = new ReflectionClosure($this->closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->reflector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method used to map closure pointers.
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function mapPointers(&$data)
|
||||||
|
{
|
||||||
|
$scope = $this->scope;
|
||||||
|
|
||||||
|
if ($data instanceof static) {
|
||||||
|
$data = &$data->closure;
|
||||||
|
} elseif (is_array($data)) {
|
||||||
|
if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[self::ARRAY_RECURSIVE_KEY] = true;
|
||||||
|
|
||||||
|
foreach ($data as $key => &$value) {
|
||||||
|
if ($key === self::ARRAY_RECURSIVE_KEY) {
|
||||||
|
continue;
|
||||||
|
} elseif ($value instanceof static) {
|
||||||
|
$data[$key] = &$value->closure;
|
||||||
|
} elseif ($value instanceof SelfReference && $value->hash === $this->code['self']) {
|
||||||
|
$data[$key] = &$this->closure;
|
||||||
|
} else {
|
||||||
|
$this->mapPointers($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($value);
|
||||||
|
unset($data[self::ARRAY_RECURSIVE_KEY]);
|
||||||
|
} elseif ($data instanceof \stdClass) {
|
||||||
|
if (isset($scope[$data])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope[$data] = true;
|
||||||
|
|
||||||
|
foreach ($data as $key => &$value) {
|
||||||
|
if ($value instanceof SelfReference && $value->hash === $this->code['self']) {
|
||||||
|
$data->{$key} = &$this->closure;
|
||||||
|
} elseif (is_array($value) || is_object($value)) {
|
||||||
|
$this->mapPointers($value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($value);
|
||||||
|
} elseif (is_object($data) && ! ($data instanceof Closure)) {
|
||||||
|
if (isset($scope[$data])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope[$data] = true;
|
||||||
|
$reflection = new ReflectionObject($data);
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (! $reflection->isUserDefined()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($reflection->getProperties() as $property) {
|
||||||
|
if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$property->setAccessible(true);
|
||||||
|
|
||||||
|
if (! $property->isInitialized($data) || $property->isReadOnly()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = $property->getValue($data);
|
||||||
|
|
||||||
|
if ($item instanceof SerializableClosure || $item instanceof UnsignedSerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) {
|
||||||
|
$this->code['objects'][] = [
|
||||||
|
'instance' => $data,
|
||||||
|
'property' => $property,
|
||||||
|
'object' => $item instanceof SelfReference ? $this : $item,
|
||||||
|
];
|
||||||
|
} elseif (is_array($item) || is_object($item)) {
|
||||||
|
$this->mapPointers($item);
|
||||||
|
$property->setValue($data, $item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while ($reflection = $reflection->getParentClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal method used to map closures by reference.
|
||||||
|
*
|
||||||
|
* @param mixed $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function mapByReference(&$data)
|
||||||
|
{
|
||||||
|
if ($data instanceof Closure) {
|
||||||
|
if ($data === $this->closure) {
|
||||||
|
$data = new SelfReference($this->reference);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->scope[$data])) {
|
||||||
|
$data = $this->scope[$data];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$instance = new static($data);
|
||||||
|
|
||||||
|
$instance->scope = $this->scope;
|
||||||
|
|
||||||
|
$data = $this->scope[$data] = $instance;
|
||||||
|
} elseif (is_array($data)) {
|
||||||
|
if (isset($data[self::ARRAY_RECURSIVE_KEY])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data[self::ARRAY_RECURSIVE_KEY] = true;
|
||||||
|
|
||||||
|
foreach ($data as $key => &$value) {
|
||||||
|
if ($key === self::ARRAY_RECURSIVE_KEY) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->mapByReference($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($value);
|
||||||
|
unset($data[self::ARRAY_RECURSIVE_KEY]);
|
||||||
|
} elseif ($data instanceof \stdClass) {
|
||||||
|
if (isset($this->scope[$data])) {
|
||||||
|
$data = $this->scope[$data];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$instance = $data;
|
||||||
|
$this->scope[$instance] = $data = clone $data;
|
||||||
|
|
||||||
|
foreach ($data as &$value) {
|
||||||
|
$this->mapByReference($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($value);
|
||||||
|
} elseif (is_object($data) && ! $data instanceof SerializableClosure && ! $data instanceof UnsignedSerializableClosure) {
|
||||||
|
if (isset($this->scope[$data])) {
|
||||||
|
$data = $this->scope[$data];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$instance = $data;
|
||||||
|
|
||||||
|
if ($data instanceof DateTimeInterface) {
|
||||||
|
$this->scope[$instance] = $data;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data instanceof UnitEnum) {
|
||||||
|
$this->scope[$instance] = $data;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflection = new ReflectionObject($data);
|
||||||
|
|
||||||
|
if (! $reflection->isUserDefined()) {
|
||||||
|
$this->scope[$instance] = $data;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->scope[$instance] = $data = $reflection->newInstanceWithoutConstructor();
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (! $reflection->isUserDefined()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($reflection->getProperties() as $property) {
|
||||||
|
if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined() || $this->isVirtualProperty($property)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$property->setAccessible(true);
|
||||||
|
|
||||||
|
if (! $property->isInitialized($instance) || ($property->isReadOnly() && $property->class !== $reflection->name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $property->getValue($instance);
|
||||||
|
|
||||||
|
if (is_array($value) || is_object($value)) {
|
||||||
|
$this->mapByReference($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$property->setValue($data, $value);
|
||||||
|
}
|
||||||
|
} while ($reflection = $reflection->getParentClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine is virtual property.
|
||||||
|
*
|
||||||
|
* @param \ReflectionProperty $property
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function isVirtualProperty(ReflectionProperty $property): bool
|
||||||
|
{
|
||||||
|
return method_exists($property, 'isVirtual') && $property->isVirtual();
|
||||||
|
}
|
||||||
|
}
|
||||||
91
api/vendor/laravel/serializable-closure/src/Serializers/Signed.php
vendored
Normal file
91
api/vendor/laravel/serializable-closure/src/Serializers/Signed.php
vendored
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Serializers;
|
||||||
|
|
||||||
|
use Laravel\SerializableClosure\Contracts\Serializable;
|
||||||
|
use Laravel\SerializableClosure\Exceptions\InvalidSignatureException;
|
||||||
|
use Laravel\SerializableClosure\Exceptions\MissingSecretKeyException;
|
||||||
|
|
||||||
|
class Signed implements Serializable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The signer that will sign and verify the closure's signature.
|
||||||
|
*
|
||||||
|
* @var \Laravel\SerializableClosure\Contracts\Signer|null
|
||||||
|
*/
|
||||||
|
public static $signer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The closure to be serialized/unserialized.
|
||||||
|
*
|
||||||
|
* @var \Closure
|
||||||
|
*/
|
||||||
|
protected $closure;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new serializable closure instance.
|
||||||
|
*
|
||||||
|
* @param \Closure $closure
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($closure)
|
||||||
|
{
|
||||||
|
$this->closure = $closure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the closure with the given arguments.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __invoke()
|
||||||
|
{
|
||||||
|
return call_user_func_array($this->closure, func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the closure.
|
||||||
|
*
|
||||||
|
* @return \Closure
|
||||||
|
*/
|
||||||
|
public function getClosure()
|
||||||
|
{
|
||||||
|
return $this->closure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the serializable representation of the closure.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function __serialize()
|
||||||
|
{
|
||||||
|
if (! static::$signer) {
|
||||||
|
throw new MissingSecretKeyException();
|
||||||
|
}
|
||||||
|
|
||||||
|
return static::$signer->sign(
|
||||||
|
serialize(new Native($this->closure))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the closure after serialization.
|
||||||
|
*
|
||||||
|
* @param array{serializable: string, hash: string} $signature
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException
|
||||||
|
*/
|
||||||
|
public function __unserialize($signature)
|
||||||
|
{
|
||||||
|
if (static::$signer && ! static::$signer->verify($signature)) {
|
||||||
|
throw new InvalidSignatureException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \Laravel\SerializableClosure\Contracts\Serializable $serializable */
|
||||||
|
$serializable = unserialize($signature['serializable']);
|
||||||
|
|
||||||
|
$this->closure = $serializable->getClosure();
|
||||||
|
}
|
||||||
|
}
|
||||||
53
api/vendor/laravel/serializable-closure/src/Signers/Hmac.php
vendored
Normal file
53
api/vendor/laravel/serializable-closure/src/Signers/Hmac.php
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Signers;
|
||||||
|
|
||||||
|
use Laravel\SerializableClosure\Contracts\Signer;
|
||||||
|
|
||||||
|
class Hmac implements Signer
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The secret key.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $secret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new signer instance.
|
||||||
|
*
|
||||||
|
* @param string $secret
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($secret)
|
||||||
|
{
|
||||||
|
$this->secret = $secret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign the given serializable.
|
||||||
|
*
|
||||||
|
* @param string $serialized
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function sign($serialized)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'serializable' => $serialized,
|
||||||
|
'hash' => base64_encode(hash_hmac('sha256', $serialized, $this->secret, true)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the given signature.
|
||||||
|
*
|
||||||
|
* @param array{serializable: string, hash: string} $signature
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function verify($signature)
|
||||||
|
{
|
||||||
|
return hash_equals(base64_encode(
|
||||||
|
hash_hmac('sha256', $signature['serializable'], $this->secret, true)
|
||||||
|
), $signature['hash']);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
api/vendor/laravel/serializable-closure/src/Support/ClosureScope.php
vendored
Normal file
22
api/vendor/laravel/serializable-closure/src/Support/ClosureScope.php
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Support;
|
||||||
|
|
||||||
|
use SplObjectStorage;
|
||||||
|
|
||||||
|
class ClosureScope extends SplObjectStorage
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The number of serializations in current scope.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $serializations = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of closures that have to be serialized.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $toSerialize = 0;
|
||||||
|
}
|
||||||
181
api/vendor/laravel/serializable-closure/src/Support/ClosureStream.php
vendored
Normal file
181
api/vendor/laravel/serializable-closure/src/Support/ClosureStream.php
vendored
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Support;
|
||||||
|
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class ClosureStream
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The stream protocol.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const STREAM_PROTO = 'laravel-serializable-closure';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this stream is registered.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected static $isRegistered = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stream content.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stream content.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The stream pointer.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $pointer = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens file or URL.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param string $mode
|
||||||
|
* @param string $options
|
||||||
|
* @param string|null $opened_path
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function stream_open($path, $mode, $options, &$opened_path)
|
||||||
|
{
|
||||||
|
$this->content = "<?php\nreturn ".substr($path, strlen(static::STREAM_PROTO.'://')).';';
|
||||||
|
$this->length = strlen($this->content);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read from stream.
|
||||||
|
*
|
||||||
|
* @param int $count
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function stream_read($count)
|
||||||
|
{
|
||||||
|
$value = substr($this->content, $this->pointer, $count);
|
||||||
|
|
||||||
|
$this->pointer += $count;
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for end-of-file on a file pointer.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function stream_eof()
|
||||||
|
{
|
||||||
|
return $this->pointer >= $this->length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change stream options.
|
||||||
|
*
|
||||||
|
* @param int $option
|
||||||
|
* @param int $arg1
|
||||||
|
* @param int $arg2
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function stream_set_option($option, $arg1, $arg2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve information about a file resource.
|
||||||
|
*
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
public function stream_stat()
|
||||||
|
{
|
||||||
|
$stat = stat(__FILE__);
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
|
$stat[7] = $stat['size'] = $this->length;
|
||||||
|
|
||||||
|
return $stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve information about a file.
|
||||||
|
*
|
||||||
|
* @param string $path
|
||||||
|
* @param int $flags
|
||||||
|
* @return array|bool
|
||||||
|
*/
|
||||||
|
public function url_stat($path, $flags)
|
||||||
|
{
|
||||||
|
$stat = stat(__FILE__);
|
||||||
|
// @phpstan-ignore-next-line
|
||||||
|
$stat[7] = $stat['size'] = $this->length;
|
||||||
|
|
||||||
|
return $stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seeks to specific location in a stream.
|
||||||
|
*
|
||||||
|
* @param int $offset
|
||||||
|
* @param int $whence
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function stream_seek($offset, $whence = SEEK_SET)
|
||||||
|
{
|
||||||
|
$crt = $this->pointer;
|
||||||
|
|
||||||
|
switch ($whence) {
|
||||||
|
case SEEK_SET:
|
||||||
|
$this->pointer = $offset;
|
||||||
|
break;
|
||||||
|
case SEEK_CUR:
|
||||||
|
$this->pointer += $offset;
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
$this->pointer = $this->length + $offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->pointer < 0 || $this->pointer >= $this->length) {
|
||||||
|
$this->pointer = $crt;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the current position of a stream.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function stream_tell()
|
||||||
|
{
|
||||||
|
return $this->pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the stream.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function register()
|
||||||
|
{
|
||||||
|
if (! static::$isRegistered) {
|
||||||
|
static::$isRegistered = stream_wrapper_register(static::STREAM_PROTO, __CLASS__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1243
api/vendor/laravel/serializable-closure/src/Support/ReflectionClosure.php
vendored
Normal file
1243
api/vendor/laravel/serializable-closure/src/Support/ReflectionClosure.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
24
api/vendor/laravel/serializable-closure/src/Support/SelfReference.php
vendored
Normal file
24
api/vendor/laravel/serializable-closure/src/Support/SelfReference.php
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure\Support;
|
||||||
|
|
||||||
|
class SelfReference
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The unique hash representing the object.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $hash;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new self reference instance.
|
||||||
|
*
|
||||||
|
* @param string $hash
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($hash)
|
||||||
|
{
|
||||||
|
$this->hash = $hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
69
api/vendor/laravel/serializable-closure/src/UnsignedSerializableClosure.php
vendored
Normal file
69
api/vendor/laravel/serializable-closure/src/UnsignedSerializableClosure.php
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Laravel\SerializableClosure;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
|
||||||
|
class UnsignedSerializableClosure
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The closure's serializable.
|
||||||
|
*
|
||||||
|
* @var \Laravel\SerializableClosure\Contracts\Serializable
|
||||||
|
*/
|
||||||
|
protected $serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new serializable closure instance.
|
||||||
|
*
|
||||||
|
* @param \Closure $closure
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct(Closure $closure)
|
||||||
|
{
|
||||||
|
$this->serializable = new Serializers\Native($closure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the closure with the given arguments.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __invoke()
|
||||||
|
{
|
||||||
|
return call_user_func_array($this->serializable, func_get_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the closure.
|
||||||
|
*
|
||||||
|
* @return \Closure
|
||||||
|
*/
|
||||||
|
public function getClosure()
|
||||||
|
{
|
||||||
|
return $this->serializable->getClosure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the serializable representation of the closure.
|
||||||
|
*
|
||||||
|
* @return array{serializable: \Laravel\SerializableClosure\Contracts\Serializable}
|
||||||
|
*/
|
||||||
|
public function __serialize()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'serializable' => $this->serializable,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the closure after serialization.
|
||||||
|
*
|
||||||
|
* @param array{serializable: \Laravel\SerializableClosure\Contracts\Serializable} $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __unserialize($data)
|
||||||
|
{
|
||||||
|
$this->serializable = $data['serializable'];
|
||||||
|
}
|
||||||
|
}
|
||||||
5
api/vendor/nikic/fast-route/.gitignore
vendored
Normal file
5
api/vendor/nikic/fast-route/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/vendor/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# ignore lock file since we have no extra dependencies
|
||||||
|
composer.lock
|
||||||
1
api/vendor/nikic/fast-route/.hhconfig
vendored
Normal file
1
api/vendor/nikic/fast-route/.hhconfig
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
assume_php=false
|
||||||
20
api/vendor/nikic/fast-route/.travis.yml
vendored
Normal file
20
api/vendor/nikic/fast-route/.travis.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
sudo: false
|
||||||
|
language: php
|
||||||
|
|
||||||
|
php:
|
||||||
|
- 5.4
|
||||||
|
- 5.5
|
||||||
|
- 5.6
|
||||||
|
- 7.0
|
||||||
|
- 7.1
|
||||||
|
- 7.2
|
||||||
|
- hhvm
|
||||||
|
|
||||||
|
script:
|
||||||
|
- ./vendor/bin/phpunit
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- travis_retry composer self-update
|
||||||
|
|
||||||
|
install:
|
||||||
|
- composer install
|
||||||
126
api/vendor/nikic/fast-route/FastRoute.hhi
vendored
Normal file
126
api/vendor/nikic/fast-route/FastRoute.hhi
vendored
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?hh // decl
|
||||||
|
|
||||||
|
namespace FastRoute {
|
||||||
|
class BadRouteException extends \LogicException {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RouteParser {
|
||||||
|
public function parse(string $route): array<array>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RouteCollector {
|
||||||
|
public function __construct(RouteParser $routeParser, DataGenerator $dataGenerator);
|
||||||
|
public function addRoute(mixed $httpMethod, string $route, mixed $handler): void;
|
||||||
|
public function getData(): array;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Route {
|
||||||
|
public function __construct(string $httpMethod, mixed $handler, string $regex, array $variables);
|
||||||
|
public function matches(string $str): bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DataGenerator {
|
||||||
|
public function addRoute(string $httpMethod, array $routeData, mixed $handler);
|
||||||
|
public function getData(): array;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dispatcher {
|
||||||
|
const int NOT_FOUND = 0;
|
||||||
|
const int FOUND = 1;
|
||||||
|
const int METHOD_NOT_ALLOWED = 2;
|
||||||
|
public function dispatch(string $httpMethod, string $uri): array;
|
||||||
|
}
|
||||||
|
|
||||||
|
function simpleDispatcher(
|
||||||
|
(function(RouteCollector): void) $routeDefinitionCallback,
|
||||||
|
shape(
|
||||||
|
?'routeParser' => classname<RouteParser>,
|
||||||
|
?'dataGenerator' => classname<DataGenerator>,
|
||||||
|
?'dispatcher' => classname<Dispatcher>,
|
||||||
|
?'routeCollector' => classname<RouteCollector>,
|
||||||
|
) $options = shape()): Dispatcher;
|
||||||
|
|
||||||
|
function cachedDispatcher(
|
||||||
|
(function(RouteCollector): void) $routeDefinitionCallback,
|
||||||
|
shape(
|
||||||
|
?'routeParser' => classname<RouteParser>,
|
||||||
|
?'dataGenerator' => classname<DataGenerator>,
|
||||||
|
?'dispatcher' => classname<Dispatcher>,
|
||||||
|
?'routeCollector' => classname<RouteCollector>,
|
||||||
|
?'cacheDisabled' => bool,
|
||||||
|
?'cacheFile' => string,
|
||||||
|
) $options = shape()): Dispatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace FastRoute\DataGenerator {
|
||||||
|
abstract class RegexBasedAbstract implements \FastRoute\DataGenerator {
|
||||||
|
protected abstract function getApproxChunkSize();
|
||||||
|
protected abstract function processChunk($regexToRoutesMap);
|
||||||
|
|
||||||
|
public function addRoute(string $httpMethod, array $routeData, mixed $handler): void;
|
||||||
|
public function getData(): array;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CharCountBased extends RegexBasedAbstract {
|
||||||
|
protected function getApproxChunkSize(): int;
|
||||||
|
protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GroupCountBased extends RegexBasedAbstract {
|
||||||
|
protected function getApproxChunkSize(): int;
|
||||||
|
protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GroupPosBased extends RegexBasedAbstract {
|
||||||
|
protected function getApproxChunkSize(): int;
|
||||||
|
protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MarkBased extends RegexBasedAbstract {
|
||||||
|
protected function getApproxChunkSize(): int;
|
||||||
|
protected function processChunk(array<string, string> $regexToRoutesMap): array<string, mixed>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher {
|
||||||
|
abstract class RegexBasedAbstract implements \FastRoute\Dispatcher {
|
||||||
|
protected abstract function dispatchVariableRoute(array<array> $routeData, string $uri): array;
|
||||||
|
|
||||||
|
public function dispatch(string $httpMethod, string $uri): array;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GroupPosBased extends RegexBasedAbstract {
|
||||||
|
public function __construct(array $data);
|
||||||
|
protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;
|
||||||
|
}
|
||||||
|
|
||||||
|
class GroupCountBased extends RegexBasedAbstract {
|
||||||
|
public function __construct(array $data);
|
||||||
|
protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CharCountBased extends RegexBasedAbstract {
|
||||||
|
public function __construct(array $data);
|
||||||
|
protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MarkBased extends RegexBasedAbstract {
|
||||||
|
public function __construct(array $data);
|
||||||
|
protected function dispatchVariableRoute(array<array> $routeData, string $uri): array;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace FastRoute\RouteParser {
|
||||||
|
class Std implements \FastRoute\RouteParser {
|
||||||
|
const string VARIABLE_REGEX = <<<'REGEX'
|
||||||
|
\{
|
||||||
|
\s* ([a-zA-Z][a-zA-Z0-9_]*) \s*
|
||||||
|
(?:
|
||||||
|
: \s* ([^{}]*(?:\{(?-1)\}[^{}]*)*)
|
||||||
|
)?
|
||||||
|
\}
|
||||||
|
REGEX;
|
||||||
|
const string DEFAULT_DISPATCH_REGEX = '[^/]+';
|
||||||
|
public function parse(string $route): array<array>;
|
||||||
|
}
|
||||||
|
}
|
||||||
31
api/vendor/nikic/fast-route/LICENSE
vendored
Normal file
31
api/vendor/nikic/fast-route/LICENSE
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Copyright (c) 2013 by Nikita Popov.
|
||||||
|
|
||||||
|
Some rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials provided
|
||||||
|
with the distribution.
|
||||||
|
|
||||||
|
* The names of the contributors may not be used to endorse or
|
||||||
|
promote products derived from this software without specific
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
313
api/vendor/nikic/fast-route/README.md
vendored
Normal file
313
api/vendor/nikic/fast-route/README.md
vendored
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
FastRoute - Fast request router for PHP
|
||||||
|
=======================================
|
||||||
|
|
||||||
|
This library provides a fast implementation of a regular expression based router. [Blog post explaining how the
|
||||||
|
implementation works and why it is fast.][blog_post]
|
||||||
|
|
||||||
|
Install
|
||||||
|
-------
|
||||||
|
|
||||||
|
To install with composer:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
composer require nikic/fast-route
|
||||||
|
```
|
||||||
|
|
||||||
|
Requires PHP 5.4 or newer.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
Here's a basic usage example:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require '/path/to/vendor/autoload.php';
|
||||||
|
|
||||||
|
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/users', 'get_all_users_handler');
|
||||||
|
// {id} must be a number (\d+)
|
||||||
|
$r->addRoute('GET', '/user/{id:\d+}', 'get_user_handler');
|
||||||
|
// The /{title} suffix is optional
|
||||||
|
$r->addRoute('GET', '/articles/{id:\d+}[/{title}]', 'get_article_handler');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fetch method and URI from somewhere
|
||||||
|
$httpMethod = $_SERVER['REQUEST_METHOD'];
|
||||||
|
$uri = $_SERVER['REQUEST_URI'];
|
||||||
|
|
||||||
|
// Strip query string (?foo=bar) and decode URI
|
||||||
|
if (false !== $pos = strpos($uri, '?')) {
|
||||||
|
$uri = substr($uri, 0, $pos);
|
||||||
|
}
|
||||||
|
$uri = rawurldecode($uri);
|
||||||
|
|
||||||
|
$routeInfo = $dispatcher->dispatch($httpMethod, $uri);
|
||||||
|
switch ($routeInfo[0]) {
|
||||||
|
case FastRoute\Dispatcher::NOT_FOUND:
|
||||||
|
// ... 404 Not Found
|
||||||
|
break;
|
||||||
|
case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
|
||||||
|
$allowedMethods = $routeInfo[1];
|
||||||
|
// ... 405 Method Not Allowed
|
||||||
|
break;
|
||||||
|
case FastRoute\Dispatcher::FOUND:
|
||||||
|
$handler = $routeInfo[1];
|
||||||
|
$vars = $routeInfo[2];
|
||||||
|
// ... call $handler with $vars
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Defining routes
|
||||||
|
|
||||||
|
The routes are defined by calling the `FastRoute\simpleDispatcher()` function, which accepts
|
||||||
|
a callable taking a `FastRoute\RouteCollector` instance. The routes are added by calling
|
||||||
|
`addRoute()` on the collector instance:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$r->addRoute($method, $routePattern, $handler);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `$method` is an uppercase HTTP method string for which a certain route should match. It
|
||||||
|
is possible to specify multiple valid methods using an array:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// These two calls
|
||||||
|
$r->addRoute('GET', '/test', 'handler');
|
||||||
|
$r->addRoute('POST', '/test', 'handler');
|
||||||
|
// Are equivalent to this one call
|
||||||
|
$r->addRoute(['GET', 'POST'], '/test', 'handler');
|
||||||
|
```
|
||||||
|
|
||||||
|
By default the `$routePattern` uses a syntax where `{foo}` specifies a placeholder with name `foo`
|
||||||
|
and matching the regex `[^/]+`. To adjust the pattern the placeholder matches, you can specify
|
||||||
|
a custom pattern by writing `{bar:[0-9]+}`. Some examples:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Matches /user/42, but not /user/xyz
|
||||||
|
$r->addRoute('GET', '/user/{id:\d+}', 'handler');
|
||||||
|
|
||||||
|
// Matches /user/foobar, but not /user/foo/bar
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler');
|
||||||
|
|
||||||
|
// Matches /user/foo/bar as well
|
||||||
|
$r->addRoute('GET', '/user/{name:.+}', 'handler');
|
||||||
|
```
|
||||||
|
|
||||||
|
Custom patterns for route placeholders cannot use capturing groups. For example `{lang:(en|de)}`
|
||||||
|
is not a valid placeholder, because `()` is a capturing group. Instead you can use either
|
||||||
|
`{lang:en|de}` or `{lang:(?:en|de)}`.
|
||||||
|
|
||||||
|
Furthermore parts of the route enclosed in `[...]` are considered optional, so that `/foo[bar]`
|
||||||
|
will match both `/foo` and `/foobar`. Optional parts are only supported in a trailing position,
|
||||||
|
not in the middle of a route.
|
||||||
|
|
||||||
|
```php
|
||||||
|
// This route
|
||||||
|
$r->addRoute('GET', '/user/{id:\d+}[/{name}]', 'handler');
|
||||||
|
// Is equivalent to these two routes
|
||||||
|
$r->addRoute('GET', '/user/{id:\d+}', 'handler');
|
||||||
|
$r->addRoute('GET', '/user/{id:\d+}/{name}', 'handler');
|
||||||
|
|
||||||
|
// Multiple nested optional parts are possible as well
|
||||||
|
$r->addRoute('GET', '/user[/{id:\d+}[/{name}]]', 'handler');
|
||||||
|
|
||||||
|
// This route is NOT valid, because optional parts can only occur at the end
|
||||||
|
$r->addRoute('GET', '/user[/{id:\d+}]/{name}', 'handler');
|
||||||
|
```
|
||||||
|
|
||||||
|
The `$handler` parameter does not necessarily have to be a callback, it could also be a controller
|
||||||
|
class name or any other kind of data you wish to associate with the route. FastRoute only tells you
|
||||||
|
which handler corresponds to your URI, how you interpret it is up to you.
|
||||||
|
|
||||||
|
#### Shorcut methods for common request methods
|
||||||
|
|
||||||
|
For the `GET`, `POST`, `PUT`, `PATCH`, `DELETE` and `HEAD` request methods shortcut methods are available. For example:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$r->get('/get-route', 'get_handler');
|
||||||
|
$r->post('/post-route', 'post_handler');
|
||||||
|
```
|
||||||
|
|
||||||
|
Is equivalent to:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$r->addRoute('GET', '/get-route', 'get_handler');
|
||||||
|
$r->addRoute('POST', '/post-route', 'post_handler');
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Route Groups
|
||||||
|
|
||||||
|
Additionally, you can specify routes inside of a group. All routes defined inside a group will have a common prefix.
|
||||||
|
|
||||||
|
For example, defining your routes as:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$r->addGroup('/admin', function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/do-something', 'handler');
|
||||||
|
$r->addRoute('GET', '/do-another-thing', 'handler');
|
||||||
|
$r->addRoute('GET', '/do-something-else', 'handler');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Will have the same result as:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$r->addRoute('GET', '/admin/do-something', 'handler');
|
||||||
|
$r->addRoute('GET', '/admin/do-another-thing', 'handler');
|
||||||
|
$r->addRoute('GET', '/admin/do-something-else', 'handler');
|
||||||
|
```
|
||||||
|
|
||||||
|
Nested groups are also supported, in which case the prefixes of all the nested groups are combined.
|
||||||
|
|
||||||
|
### Caching
|
||||||
|
|
||||||
|
The reason `simpleDispatcher` accepts a callback for defining the routes is to allow seamless
|
||||||
|
caching. By using `cachedDispatcher` instead of `simpleDispatcher` you can cache the generated
|
||||||
|
routing data and construct the dispatcher from the cached information:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$dispatcher = FastRoute\cachedDispatcher(function(FastRoute\RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
|
||||||
|
$r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler2');
|
||||||
|
}, [
|
||||||
|
'cacheFile' => __DIR__ . '/route.cache', /* required */
|
||||||
|
'cacheDisabled' => IS_DEBUG_ENABLED, /* optional, enabled by default */
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
The second parameter to the function is an options array, which can be used to specify the cache
|
||||||
|
file location, among other things.
|
||||||
|
|
||||||
|
### Dispatching a URI
|
||||||
|
|
||||||
|
A URI is dispatched by calling the `dispatch()` method of the created dispatcher. This method
|
||||||
|
accepts the HTTP method and a URI. Getting those two bits of information (and normalizing them
|
||||||
|
appropriately) is your job - this library is not bound to the PHP web SAPIs.
|
||||||
|
|
||||||
|
The `dispatch()` method returns an array whose first element contains a status code. It is one
|
||||||
|
of `Dispatcher::NOT_FOUND`, `Dispatcher::METHOD_NOT_ALLOWED` and `Dispatcher::FOUND`. For the
|
||||||
|
method not allowed status the second array element contains a list of HTTP methods allowed for
|
||||||
|
the supplied URI. For example:
|
||||||
|
|
||||||
|
[FastRoute\Dispatcher::METHOD_NOT_ALLOWED, ['GET', 'POST']]
|
||||||
|
|
||||||
|
> **NOTE:** The HTTP specification requires that a `405 Method Not Allowed` response include the
|
||||||
|
`Allow:` header to detail available methods for the requested resource. Applications using FastRoute
|
||||||
|
should use the second array element to add this header when relaying a 405 response.
|
||||||
|
|
||||||
|
For the found status the second array element is the handler that was associated with the route
|
||||||
|
and the third array element is a dictionary of placeholder names to their values. For example:
|
||||||
|
|
||||||
|
/* Routing against GET /user/nikic/42 */
|
||||||
|
|
||||||
|
[FastRoute\Dispatcher::FOUND, 'handler0', ['name' => 'nikic', 'id' => '42']]
|
||||||
|
|
||||||
|
### Overriding the route parser and dispatcher
|
||||||
|
|
||||||
|
The routing process makes use of three components: A route parser, a data generator and a
|
||||||
|
dispatcher. The three components adhere to the following interfaces:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
interface RouteParser {
|
||||||
|
public function parse($route);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DataGenerator {
|
||||||
|
public function addRoute($httpMethod, $routeData, $handler);
|
||||||
|
public function getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dispatcher {
|
||||||
|
const NOT_FOUND = 0, FOUND = 1, METHOD_NOT_ALLOWED = 2;
|
||||||
|
|
||||||
|
public function dispatch($httpMethod, $uri);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The route parser takes a route pattern string and converts it into an array of route infos, where
|
||||||
|
each route info is again an array of it's parts. The structure is best understood using an example:
|
||||||
|
|
||||||
|
/* The route /user/{id:\d+}[/{name}] converts to the following array: */
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'/user/',
|
||||||
|
['id', '\d+'],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/user/',
|
||||||
|
['id', '\d+'],
|
||||||
|
'/',
|
||||||
|
['name', '[^/]+'],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
This array can then be passed to the `addRoute()` method of a data generator. After all routes have
|
||||||
|
been added the `getData()` of the generator is invoked, which returns all the routing data required
|
||||||
|
by the dispatcher. The format of this data is not further specified - it is tightly coupled to
|
||||||
|
the corresponding dispatcher.
|
||||||
|
|
||||||
|
The dispatcher accepts the routing data via a constructor and provides a `dispatch()` method, which
|
||||||
|
you're already familiar with.
|
||||||
|
|
||||||
|
The route parser can be overwritten individually (to make use of some different pattern syntax),
|
||||||
|
however the data generator and dispatcher should always be changed as a pair, as the output from
|
||||||
|
the former is tightly coupled to the input of the latter. The reason the generator and the
|
||||||
|
dispatcher are separate is that only the latter is needed when using caching (as the output of
|
||||||
|
the former is what is being cached.)
|
||||||
|
|
||||||
|
When using the `simpleDispatcher` / `cachedDispatcher` functions from above the override happens
|
||||||
|
through the options array:
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
|
||||||
|
/* ... */
|
||||||
|
}, [
|
||||||
|
'routeParser' => 'FastRoute\\RouteParser\\Std',
|
||||||
|
'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased',
|
||||||
|
'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased',
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
The above options array corresponds to the defaults. By replacing `GroupCountBased` by
|
||||||
|
`GroupPosBased` you could switch to a different dispatching strategy.
|
||||||
|
|
||||||
|
### A Note on HEAD Requests
|
||||||
|
|
||||||
|
The HTTP spec requires servers to [support both GET and HEAD methods][2616-511]:
|
||||||
|
|
||||||
|
> The methods GET and HEAD MUST be supported by all general-purpose servers
|
||||||
|
|
||||||
|
To avoid forcing users to manually register HEAD routes for each resource we fallback to matching an
|
||||||
|
available GET route for a given resource. The PHP web SAPI transparently removes the entity body
|
||||||
|
from HEAD responses so this behavior has no effect on the vast majority of users.
|
||||||
|
|
||||||
|
However, implementers using FastRoute outside the web SAPI environment (e.g. a custom server) MUST
|
||||||
|
NOT send entity bodies generated in response to HEAD requests. If you are a non-SAPI user this is
|
||||||
|
*your responsibility*; FastRoute has no purview to prevent you from breaking HTTP in such cases.
|
||||||
|
|
||||||
|
Finally, note that applications MAY always specify their own HEAD method route for a given
|
||||||
|
resource to bypass this behavior entirely.
|
||||||
|
|
||||||
|
### Credits
|
||||||
|
|
||||||
|
This library is based on a router that [Levi Morrison][levi] implemented for the Aerys server.
|
||||||
|
|
||||||
|
A large number of tests, as well as HTTP compliance considerations, were provided by [Daniel Lowrey][rdlowrey].
|
||||||
|
|
||||||
|
|
||||||
|
[2616-511]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1 "RFC 2616 Section 5.1.1"
|
||||||
|
[blog_post]: http://nikic.github.io/2014/02/18/Fast-request-routing-using-regular-expressions.html
|
||||||
|
[levi]: https://github.com/morrisonlevi
|
||||||
|
[rdlowrey]: https://github.com/rdlowrey
|
||||||
24
api/vendor/nikic/fast-route/composer.json
vendored
Normal file
24
api/vendor/nikic/fast-route/composer.json
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"name": "nikic/fast-route",
|
||||||
|
"description": "Fast request router for PHP",
|
||||||
|
"keywords": ["routing", "router"],
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Nikita Popov",
|
||||||
|
"email": "nikic@php.net"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"FastRoute\\": "src/"
|
||||||
|
},
|
||||||
|
"files": ["src/functions.php"]
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.35|~5.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
24
api/vendor/nikic/fast-route/phpunit.xml
vendored
Normal file
24
api/vendor/nikic/fast-route/phpunit.xml
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<phpunit backupGlobals="false"
|
||||||
|
backupStaticAttributes="false"
|
||||||
|
colors="true"
|
||||||
|
convertErrorsToExceptions="true"
|
||||||
|
convertNoticesToExceptions="true"
|
||||||
|
convertWarningsToExceptions="true"
|
||||||
|
processIsolation="false"
|
||||||
|
syntaxCheck="false"
|
||||||
|
bootstrap="test/bootstrap.php"
|
||||||
|
>
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="FastRoute Tests">
|
||||||
|
<directory>./test/</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
|
||||||
|
<filter>
|
||||||
|
<whitelist>
|
||||||
|
<directory>./src/</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
||||||
28
api/vendor/nikic/fast-route/psalm.xml
vendored
Normal file
28
api/vendor/nikic/fast-route/psalm.xml
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<psalm
|
||||||
|
name="Example Psalm config with recommended defaults"
|
||||||
|
stopOnFirstError="false"
|
||||||
|
useDocblockTypes="true"
|
||||||
|
totallyTyped="false"
|
||||||
|
requireVoidReturnType="false"
|
||||||
|
>
|
||||||
|
<projectFiles>
|
||||||
|
<directory name="src" />
|
||||||
|
</projectFiles>
|
||||||
|
|
||||||
|
<issueHandlers>
|
||||||
|
<LessSpecificReturnType errorLevel="info" />
|
||||||
|
|
||||||
|
<!-- level 3 issues - slightly lazy code writing, but provably low false-negatives -->
|
||||||
|
<DeprecatedMethod errorLevel="info" />
|
||||||
|
|
||||||
|
<MissingClosureReturnType errorLevel="info" />
|
||||||
|
<MissingReturnType errorLevel="info" />
|
||||||
|
<MissingPropertyType errorLevel="info" />
|
||||||
|
<InvalidDocblock errorLevel="info" />
|
||||||
|
<MisplacedRequiredParam errorLevel="info" />
|
||||||
|
|
||||||
|
<PropertyNotSetInConstructor errorLevel="info" />
|
||||||
|
<MissingConstructor errorLevel="info" />
|
||||||
|
</issueHandlers>
|
||||||
|
</psalm>
|
||||||
7
api/vendor/nikic/fast-route/src/BadRouteException.php
vendored
Normal file
7
api/vendor/nikic/fast-route/src/BadRouteException.php
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
class BadRouteException extends \LogicException
|
||||||
|
{
|
||||||
|
}
|
||||||
26
api/vendor/nikic/fast-route/src/DataGenerator.php
vendored
Normal file
26
api/vendor/nikic/fast-route/src/DataGenerator.php
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
interface DataGenerator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Adds a route to the data generator. The route data uses the
|
||||||
|
* same format that is returned by RouterParser::parser().
|
||||||
|
*
|
||||||
|
* The handler doesn't necessarily need to be a callable, it
|
||||||
|
* can be arbitrary data that will be returned when the route
|
||||||
|
* matches.
|
||||||
|
*
|
||||||
|
* @param string $httpMethod
|
||||||
|
* @param array $routeData
|
||||||
|
* @param mixed $handler
|
||||||
|
*/
|
||||||
|
public function addRoute($httpMethod, $routeData, $handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns dispatcher data in some unspecified format, which
|
||||||
|
* depends on the used method of dispatch.
|
||||||
|
*/
|
||||||
|
public function getData();
|
||||||
|
}
|
||||||
31
api/vendor/nikic/fast-route/src/DataGenerator/CharCountBased.php
vendored
Normal file
31
api/vendor/nikic/fast-route/src/DataGenerator/CharCountBased.php
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\DataGenerator;
|
||||||
|
|
||||||
|
class CharCountBased extends RegexBasedAbstract
|
||||||
|
{
|
||||||
|
protected function getApproxChunkSize()
|
||||||
|
{
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processChunk($regexToRoutesMap)
|
||||||
|
{
|
||||||
|
$routeMap = [];
|
||||||
|
$regexes = [];
|
||||||
|
|
||||||
|
$suffixLen = 0;
|
||||||
|
$suffix = '';
|
||||||
|
$count = count($regexToRoutesMap);
|
||||||
|
foreach ($regexToRoutesMap as $regex => $route) {
|
||||||
|
$suffixLen++;
|
||||||
|
$suffix .= "\t";
|
||||||
|
|
||||||
|
$regexes[] = '(?:' . $regex . '/(\t{' . $suffixLen . '})\t{' . ($count - $suffixLen) . '})';
|
||||||
|
$routeMap[$suffix] = [$route->handler, $route->variables];
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex = '~^(?|' . implode('|', $regexes) . ')$~';
|
||||||
|
return ['regex' => $regex, 'suffix' => '/' . $suffix, 'routeMap' => $routeMap];
|
||||||
|
}
|
||||||
|
}
|
||||||
30
api/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php
vendored
Normal file
30
api/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\DataGenerator;
|
||||||
|
|
||||||
|
class GroupCountBased extends RegexBasedAbstract
|
||||||
|
{
|
||||||
|
protected function getApproxChunkSize()
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processChunk($regexToRoutesMap)
|
||||||
|
{
|
||||||
|
$routeMap = [];
|
||||||
|
$regexes = [];
|
||||||
|
$numGroups = 0;
|
||||||
|
foreach ($regexToRoutesMap as $regex => $route) {
|
||||||
|
$numVariables = count($route->variables);
|
||||||
|
$numGroups = max($numGroups, $numVariables);
|
||||||
|
|
||||||
|
$regexes[] = $regex . str_repeat('()', $numGroups - $numVariables);
|
||||||
|
$routeMap[$numGroups + 1] = [$route->handler, $route->variables];
|
||||||
|
|
||||||
|
++$numGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex = '~^(?|' . implode('|', $regexes) . ')$~';
|
||||||
|
return ['regex' => $regex, 'routeMap' => $routeMap];
|
||||||
|
}
|
||||||
|
}
|
||||||
27
api/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php
vendored
Normal file
27
api/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\DataGenerator;
|
||||||
|
|
||||||
|
class GroupPosBased extends RegexBasedAbstract
|
||||||
|
{
|
||||||
|
protected function getApproxChunkSize()
|
||||||
|
{
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processChunk($regexToRoutesMap)
|
||||||
|
{
|
||||||
|
$routeMap = [];
|
||||||
|
$regexes = [];
|
||||||
|
$offset = 1;
|
||||||
|
foreach ($regexToRoutesMap as $regex => $route) {
|
||||||
|
$regexes[] = $regex;
|
||||||
|
$routeMap[$offset] = [$route->handler, $route->variables];
|
||||||
|
|
||||||
|
$offset += count($route->variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex = '~^(?:' . implode('|', $regexes) . ')$~';
|
||||||
|
return ['regex' => $regex, 'routeMap' => $routeMap];
|
||||||
|
}
|
||||||
|
}
|
||||||
27
api/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php
vendored
Normal file
27
api/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\DataGenerator;
|
||||||
|
|
||||||
|
class MarkBased extends RegexBasedAbstract
|
||||||
|
{
|
||||||
|
protected function getApproxChunkSize()
|
||||||
|
{
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function processChunk($regexToRoutesMap)
|
||||||
|
{
|
||||||
|
$routeMap = [];
|
||||||
|
$regexes = [];
|
||||||
|
$markName = 'a';
|
||||||
|
foreach ($regexToRoutesMap as $regex => $route) {
|
||||||
|
$regexes[] = $regex . '(*MARK:' . $markName . ')';
|
||||||
|
$routeMap[$markName] = [$route->handler, $route->variables];
|
||||||
|
|
||||||
|
++$markName;
|
||||||
|
}
|
||||||
|
|
||||||
|
$regex = '~^(?|' . implode('|', $regexes) . ')$~';
|
||||||
|
return ['regex' => $regex, 'routeMap' => $routeMap];
|
||||||
|
}
|
||||||
|
}
|
||||||
186
api/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php
vendored
Normal file
186
api/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php
vendored
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\DataGenerator;
|
||||||
|
|
||||||
|
use FastRoute\BadRouteException;
|
||||||
|
use FastRoute\DataGenerator;
|
||||||
|
use FastRoute\Route;
|
||||||
|
|
||||||
|
abstract class RegexBasedAbstract implements DataGenerator
|
||||||
|
{
|
||||||
|
/** @var mixed[][] */
|
||||||
|
protected $staticRoutes = [];
|
||||||
|
|
||||||
|
/** @var Route[][] */
|
||||||
|
protected $methodToRegexToRoutesMap = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
abstract protected function getApproxChunkSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
abstract protected function processChunk($regexToRoutesMap);
|
||||||
|
|
||||||
|
public function addRoute($httpMethod, $routeData, $handler)
|
||||||
|
{
|
||||||
|
if ($this->isStaticRoute($routeData)) {
|
||||||
|
$this->addStaticRoute($httpMethod, $routeData, $handler);
|
||||||
|
} else {
|
||||||
|
$this->addVariableRoute($httpMethod, $routeData, $handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
if (empty($this->methodToRegexToRoutesMap)) {
|
||||||
|
return [$this->staticRoutes, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$this->staticRoutes, $this->generateVariableRouteData()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
private function generateVariableRouteData()
|
||||||
|
{
|
||||||
|
$data = [];
|
||||||
|
foreach ($this->methodToRegexToRoutesMap as $method => $regexToRoutesMap) {
|
||||||
|
$chunkSize = $this->computeChunkSize(count($regexToRoutesMap));
|
||||||
|
$chunks = array_chunk($regexToRoutesMap, $chunkSize, true);
|
||||||
|
$data[$method] = array_map([$this, 'processChunk'], $chunks);
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function computeChunkSize($count)
|
||||||
|
{
|
||||||
|
$numParts = max(1, round($count / $this->getApproxChunkSize()));
|
||||||
|
return (int) ceil($count / $numParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[]
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isStaticRoute($routeData)
|
||||||
|
{
|
||||||
|
return count($routeData) === 1 && is_string($routeData[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addStaticRoute($httpMethod, $routeData, $handler)
|
||||||
|
{
|
||||||
|
$routeStr = $routeData[0];
|
||||||
|
|
||||||
|
if (isset($this->staticRoutes[$httpMethod][$routeStr])) {
|
||||||
|
throw new BadRouteException(sprintf(
|
||||||
|
'Cannot register two routes matching "%s" for method "%s"',
|
||||||
|
$routeStr, $httpMethod
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->methodToRegexToRoutesMap[$httpMethod])) {
|
||||||
|
foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $route) {
|
||||||
|
if ($route->matches($routeStr)) {
|
||||||
|
throw new BadRouteException(sprintf(
|
||||||
|
'Static route "%s" is shadowed by previously defined variable route "%s" for method "%s"',
|
||||||
|
$routeStr, $route->regex, $httpMethod
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->staticRoutes[$httpMethod][$routeStr] = $handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function addVariableRoute($httpMethod, $routeData, $handler)
|
||||||
|
{
|
||||||
|
list($regex, $variables) = $this->buildRegexForRoute($routeData);
|
||||||
|
|
||||||
|
if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) {
|
||||||
|
throw new BadRouteException(sprintf(
|
||||||
|
'Cannot register two routes matching "%s" for method "%s"',
|
||||||
|
$regex, $httpMethod
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->methodToRegexToRoutesMap[$httpMethod][$regex] = new Route(
|
||||||
|
$httpMethod, $handler, $regex, $variables
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed[]
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
private function buildRegexForRoute($routeData)
|
||||||
|
{
|
||||||
|
$regex = '';
|
||||||
|
$variables = [];
|
||||||
|
foreach ($routeData as $part) {
|
||||||
|
if (is_string($part)) {
|
||||||
|
$regex .= preg_quote($part, '~');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($varName, $regexPart) = $part;
|
||||||
|
|
||||||
|
if (isset($variables[$varName])) {
|
||||||
|
throw new BadRouteException(sprintf(
|
||||||
|
'Cannot use the same placeholder "%s" twice', $varName
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->regexHasCapturingGroups($regexPart)) {
|
||||||
|
throw new BadRouteException(sprintf(
|
||||||
|
'Regex "%s" for parameter "%s" contains a capturing group',
|
||||||
|
$regexPart, $varName
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$variables[$varName] = $varName;
|
||||||
|
$regex .= '(' . $regexPart . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$regex, $variables];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function regexHasCapturingGroups($regex)
|
||||||
|
{
|
||||||
|
if (false === strpos($regex, '(')) {
|
||||||
|
// Needs to have at least a ( to contain a capturing group
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Semi-accurate detection for capturing groups
|
||||||
|
return (bool) preg_match(
|
||||||
|
'~
|
||||||
|
(?:
|
||||||
|
\(\?\(
|
||||||
|
| \[ [^\]\\\\]* (?: \\\\ . [^\]\\\\]* )* \]
|
||||||
|
| \\\\ .
|
||||||
|
) (*SKIP)(*FAIL) |
|
||||||
|
\(
|
||||||
|
(?!
|
||||||
|
\? (?! <(?![!=]) | P< | \' )
|
||||||
|
| \*
|
||||||
|
)
|
||||||
|
~x',
|
||||||
|
$regex
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
api/vendor/nikic/fast-route/src/Dispatcher.php
vendored
Normal file
26
api/vendor/nikic/fast-route/src/Dispatcher.php
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
interface Dispatcher
|
||||||
|
{
|
||||||
|
const NOT_FOUND = 0;
|
||||||
|
const FOUND = 1;
|
||||||
|
const METHOD_NOT_ALLOWED = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches against the provided HTTP method verb and URI.
|
||||||
|
*
|
||||||
|
* Returns array with one of the following formats:
|
||||||
|
*
|
||||||
|
* [self::NOT_FOUND]
|
||||||
|
* [self::METHOD_NOT_ALLOWED, ['GET', 'OTHER_ALLOWED_METHODS']]
|
||||||
|
* [self::FOUND, $handler, ['varName' => 'value', ...]]
|
||||||
|
*
|
||||||
|
* @param string $httpMethod
|
||||||
|
* @param string $uri
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function dispatch($httpMethod, $uri);
|
||||||
|
}
|
||||||
31
api/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php
vendored
Normal file
31
api/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
class CharCountBased extends RegexBasedAbstract
|
||||||
|
{
|
||||||
|
public function __construct($data)
|
||||||
|
{
|
||||||
|
list($this->staticRouteMap, $this->variableRouteData) = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function dispatchVariableRoute($routeData, $uri)
|
||||||
|
{
|
||||||
|
foreach ($routeData as $data) {
|
||||||
|
if (!preg_match($data['regex'], $uri . $data['suffix'], $matches)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($handler, $varNames) = $data['routeMap'][end($matches)];
|
||||||
|
|
||||||
|
$vars = [];
|
||||||
|
$i = 0;
|
||||||
|
foreach ($varNames as $varName) {
|
||||||
|
$vars[$varName] = $matches[++$i];
|
||||||
|
}
|
||||||
|
return [self::FOUND, $handler, $vars];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self::NOT_FOUND];
|
||||||
|
}
|
||||||
|
}
|
||||||
31
api/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php
vendored
Normal file
31
api/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
class GroupCountBased extends RegexBasedAbstract
|
||||||
|
{
|
||||||
|
public function __construct($data)
|
||||||
|
{
|
||||||
|
list($this->staticRouteMap, $this->variableRouteData) = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function dispatchVariableRoute($routeData, $uri)
|
||||||
|
{
|
||||||
|
foreach ($routeData as $data) {
|
||||||
|
if (!preg_match($data['regex'], $uri, $matches)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($handler, $varNames) = $data['routeMap'][count($matches)];
|
||||||
|
|
||||||
|
$vars = [];
|
||||||
|
$i = 0;
|
||||||
|
foreach ($varNames as $varName) {
|
||||||
|
$vars[$varName] = $matches[++$i];
|
||||||
|
}
|
||||||
|
return [self::FOUND, $handler, $vars];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self::NOT_FOUND];
|
||||||
|
}
|
||||||
|
}
|
||||||
33
api/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php
vendored
Normal file
33
api/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
class GroupPosBased extends RegexBasedAbstract
|
||||||
|
{
|
||||||
|
public function __construct($data)
|
||||||
|
{
|
||||||
|
list($this->staticRouteMap, $this->variableRouteData) = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function dispatchVariableRoute($routeData, $uri)
|
||||||
|
{
|
||||||
|
foreach ($routeData as $data) {
|
||||||
|
if (!preg_match($data['regex'], $uri, $matches)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find first non-empty match
|
||||||
|
for ($i = 1; '' === $matches[$i]; ++$i);
|
||||||
|
|
||||||
|
list($handler, $varNames) = $data['routeMap'][$i];
|
||||||
|
|
||||||
|
$vars = [];
|
||||||
|
foreach ($varNames as $varName) {
|
||||||
|
$vars[$varName] = $matches[$i++];
|
||||||
|
}
|
||||||
|
return [self::FOUND, $handler, $vars];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self::NOT_FOUND];
|
||||||
|
}
|
||||||
|
}
|
||||||
31
api/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php
vendored
Normal file
31
api/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
class MarkBased extends RegexBasedAbstract
|
||||||
|
{
|
||||||
|
public function __construct($data)
|
||||||
|
{
|
||||||
|
list($this->staticRouteMap, $this->variableRouteData) = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function dispatchVariableRoute($routeData, $uri)
|
||||||
|
{
|
||||||
|
foreach ($routeData as $data) {
|
||||||
|
if (!preg_match($data['regex'], $uri, $matches)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($handler, $varNames) = $data['routeMap'][$matches['MARK']];
|
||||||
|
|
||||||
|
$vars = [];
|
||||||
|
$i = 0;
|
||||||
|
foreach ($varNames as $varName) {
|
||||||
|
$vars[$varName] = $matches[++$i];
|
||||||
|
}
|
||||||
|
return [self::FOUND, $handler, $vars];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self::NOT_FOUND];
|
||||||
|
}
|
||||||
|
}
|
||||||
88
api/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php
vendored
Normal file
88
api/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
use FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
abstract class RegexBasedAbstract implements Dispatcher
|
||||||
|
{
|
||||||
|
/** @var mixed[][] */
|
||||||
|
protected $staticRouteMap = [];
|
||||||
|
|
||||||
|
/** @var mixed[] */
|
||||||
|
protected $variableRouteData = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
abstract protected function dispatchVariableRoute($routeData, $uri);
|
||||||
|
|
||||||
|
public function dispatch($httpMethod, $uri)
|
||||||
|
{
|
||||||
|
if (isset($this->staticRouteMap[$httpMethod][$uri])) {
|
||||||
|
$handler = $this->staticRouteMap[$httpMethod][$uri];
|
||||||
|
return [self::FOUND, $handler, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
$varRouteData = $this->variableRouteData;
|
||||||
|
if (isset($varRouteData[$httpMethod])) {
|
||||||
|
$result = $this->dispatchVariableRoute($varRouteData[$httpMethod], $uri);
|
||||||
|
if ($result[0] === self::FOUND) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For HEAD requests, attempt fallback to GET
|
||||||
|
if ($httpMethod === 'HEAD') {
|
||||||
|
if (isset($this->staticRouteMap['GET'][$uri])) {
|
||||||
|
$handler = $this->staticRouteMap['GET'][$uri];
|
||||||
|
return [self::FOUND, $handler, []];
|
||||||
|
}
|
||||||
|
if (isset($varRouteData['GET'])) {
|
||||||
|
$result = $this->dispatchVariableRoute($varRouteData['GET'], $uri);
|
||||||
|
if ($result[0] === self::FOUND) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If nothing else matches, try fallback routes
|
||||||
|
if (isset($this->staticRouteMap['*'][$uri])) {
|
||||||
|
$handler = $this->staticRouteMap['*'][$uri];
|
||||||
|
return [self::FOUND, $handler, []];
|
||||||
|
}
|
||||||
|
if (isset($varRouteData['*'])) {
|
||||||
|
$result = $this->dispatchVariableRoute($varRouteData['*'], $uri);
|
||||||
|
if ($result[0] === self::FOUND) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find allowed methods for this URI by matching against all other HTTP methods as well
|
||||||
|
$allowedMethods = [];
|
||||||
|
|
||||||
|
foreach ($this->staticRouteMap as $method => $uriMap) {
|
||||||
|
if ($method !== $httpMethod && isset($uriMap[$uri])) {
|
||||||
|
$allowedMethods[] = $method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($varRouteData as $method => $routeData) {
|
||||||
|
if ($method === $httpMethod) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->dispatchVariableRoute($routeData, $uri);
|
||||||
|
if ($result[0] === self::FOUND) {
|
||||||
|
$allowedMethods[] = $method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are no allowed methods the route simply does not exist
|
||||||
|
if ($allowedMethods) {
|
||||||
|
return [self::METHOD_NOT_ALLOWED, $allowedMethods];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self::NOT_FOUND];
|
||||||
|
}
|
||||||
|
}
|
||||||
47
api/vendor/nikic/fast-route/src/Route.php
vendored
Normal file
47
api/vendor/nikic/fast-route/src/Route.php
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
class Route
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
public $httpMethod;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public $regex;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
public $variables;
|
||||||
|
|
||||||
|
/** @var mixed */
|
||||||
|
public $handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a route (value object).
|
||||||
|
*
|
||||||
|
* @param string $httpMethod
|
||||||
|
* @param mixed $handler
|
||||||
|
* @param string $regex
|
||||||
|
* @param array $variables
|
||||||
|
*/
|
||||||
|
public function __construct($httpMethod, $handler, $regex, $variables)
|
||||||
|
{
|
||||||
|
$this->httpMethod = $httpMethod;
|
||||||
|
$this->handler = $handler;
|
||||||
|
$this->regex = $regex;
|
||||||
|
$this->variables = $variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether this route matches the given string.
|
||||||
|
*
|
||||||
|
* @param string $str
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function matches($str)
|
||||||
|
{
|
||||||
|
$regex = '~^' . $this->regex . '$~';
|
||||||
|
return (bool) preg_match($regex, $str);
|
||||||
|
}
|
||||||
|
}
|
||||||
152
api/vendor/nikic/fast-route/src/RouteCollector.php
vendored
Normal file
152
api/vendor/nikic/fast-route/src/RouteCollector.php
vendored
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
class RouteCollector
|
||||||
|
{
|
||||||
|
/** @var RouteParser */
|
||||||
|
protected $routeParser;
|
||||||
|
|
||||||
|
/** @var DataGenerator */
|
||||||
|
protected $dataGenerator;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $currentGroupPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a route collector.
|
||||||
|
*
|
||||||
|
* @param RouteParser $routeParser
|
||||||
|
* @param DataGenerator $dataGenerator
|
||||||
|
*/
|
||||||
|
public function __construct(RouteParser $routeParser, DataGenerator $dataGenerator)
|
||||||
|
{
|
||||||
|
$this->routeParser = $routeParser;
|
||||||
|
$this->dataGenerator = $dataGenerator;
|
||||||
|
$this->currentGroupPrefix = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a route to the collection.
|
||||||
|
*
|
||||||
|
* The syntax used in the $route string depends on the used route parser.
|
||||||
|
*
|
||||||
|
* @param string|string[] $httpMethod
|
||||||
|
* @param string $route
|
||||||
|
* @param mixed $handler
|
||||||
|
*/
|
||||||
|
public function addRoute($httpMethod, $route, $handler)
|
||||||
|
{
|
||||||
|
$route = $this->currentGroupPrefix . $route;
|
||||||
|
$routeDatas = $this->routeParser->parse($route);
|
||||||
|
foreach ((array) $httpMethod as $method) {
|
||||||
|
foreach ($routeDatas as $routeData) {
|
||||||
|
$this->dataGenerator->addRoute($method, $routeData, $handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a route group with a common prefix.
|
||||||
|
*
|
||||||
|
* All routes created in the passed callback will have the given group prefix prepended.
|
||||||
|
*
|
||||||
|
* @param string $prefix
|
||||||
|
* @param callable $callback
|
||||||
|
*/
|
||||||
|
public function addGroup($prefix, callable $callback)
|
||||||
|
{
|
||||||
|
$previousGroupPrefix = $this->currentGroupPrefix;
|
||||||
|
$this->currentGroupPrefix = $previousGroupPrefix . $prefix;
|
||||||
|
$callback($this);
|
||||||
|
$this->currentGroupPrefix = $previousGroupPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a GET route to the collection
|
||||||
|
*
|
||||||
|
* This is simply an alias of $this->addRoute('GET', $route, $handler)
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
* @param mixed $handler
|
||||||
|
*/
|
||||||
|
public function get($route, $handler)
|
||||||
|
{
|
||||||
|
$this->addRoute('GET', $route, $handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a POST route to the collection
|
||||||
|
*
|
||||||
|
* This is simply an alias of $this->addRoute('POST', $route, $handler)
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
* @param mixed $handler
|
||||||
|
*/
|
||||||
|
public function post($route, $handler)
|
||||||
|
{
|
||||||
|
$this->addRoute('POST', $route, $handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a PUT route to the collection
|
||||||
|
*
|
||||||
|
* This is simply an alias of $this->addRoute('PUT', $route, $handler)
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
* @param mixed $handler
|
||||||
|
*/
|
||||||
|
public function put($route, $handler)
|
||||||
|
{
|
||||||
|
$this->addRoute('PUT', $route, $handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a DELETE route to the collection
|
||||||
|
*
|
||||||
|
* This is simply an alias of $this->addRoute('DELETE', $route, $handler)
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
* @param mixed $handler
|
||||||
|
*/
|
||||||
|
public function delete($route, $handler)
|
||||||
|
{
|
||||||
|
$this->addRoute('DELETE', $route, $handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a PATCH route to the collection
|
||||||
|
*
|
||||||
|
* This is simply an alias of $this->addRoute('PATCH', $route, $handler)
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
* @param mixed $handler
|
||||||
|
*/
|
||||||
|
public function patch($route, $handler)
|
||||||
|
{
|
||||||
|
$this->addRoute('PATCH', $route, $handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a HEAD route to the collection
|
||||||
|
*
|
||||||
|
* This is simply an alias of $this->addRoute('HEAD', $route, $handler)
|
||||||
|
*
|
||||||
|
* @param string $route
|
||||||
|
* @param mixed $handler
|
||||||
|
*/
|
||||||
|
public function head($route, $handler)
|
||||||
|
{
|
||||||
|
$this->addRoute('HEAD', $route, $handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the collected route data, as provided by the data generator.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return $this->dataGenerator->getData();
|
||||||
|
}
|
||||||
|
}
|
||||||
37
api/vendor/nikic/fast-route/src/RouteParser.php
vendored
Normal file
37
api/vendor/nikic/fast-route/src/RouteParser.php
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
interface RouteParser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Parses a route string into multiple route data arrays.
|
||||||
|
*
|
||||||
|
* The expected output is defined using an example:
|
||||||
|
*
|
||||||
|
* For the route string "/fixedRoutePart/{varName}[/moreFixed/{varName2:\d+}]", if {varName} is interpreted as
|
||||||
|
* a placeholder and [...] is interpreted as an optional route part, the expected result is:
|
||||||
|
*
|
||||||
|
* [
|
||||||
|
* // first route: without optional part
|
||||||
|
* [
|
||||||
|
* "/fixedRoutePart/",
|
||||||
|
* ["varName", "[^/]+"],
|
||||||
|
* ],
|
||||||
|
* // second route: with optional part
|
||||||
|
* [
|
||||||
|
* "/fixedRoutePart/",
|
||||||
|
* ["varName", "[^/]+"],
|
||||||
|
* "/moreFixed/",
|
||||||
|
* ["varName2", [0-9]+"],
|
||||||
|
* ],
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* Here one route string was converted into two route data arrays.
|
||||||
|
*
|
||||||
|
* @param string $route Route string to parse
|
||||||
|
*
|
||||||
|
* @return mixed[][] Array of route data arrays
|
||||||
|
*/
|
||||||
|
public function parse($route);
|
||||||
|
}
|
||||||
87
api/vendor/nikic/fast-route/src/RouteParser/Std.php
vendored
Normal file
87
api/vendor/nikic/fast-route/src/RouteParser/Std.php
vendored
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\RouteParser;
|
||||||
|
|
||||||
|
use FastRoute\BadRouteException;
|
||||||
|
use FastRoute\RouteParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses route strings of the following form:
|
||||||
|
*
|
||||||
|
* "/user/{name}[/{id:[0-9]+}]"
|
||||||
|
*/
|
||||||
|
class Std implements RouteParser
|
||||||
|
{
|
||||||
|
const VARIABLE_REGEX = <<<'REGEX'
|
||||||
|
\{
|
||||||
|
\s* ([a-zA-Z_][a-zA-Z0-9_-]*) \s*
|
||||||
|
(?:
|
||||||
|
: \s* ([^{}]*(?:\{(?-1)\}[^{}]*)*)
|
||||||
|
)?
|
||||||
|
\}
|
||||||
|
REGEX;
|
||||||
|
const DEFAULT_DISPATCH_REGEX = '[^/]+';
|
||||||
|
|
||||||
|
public function parse($route)
|
||||||
|
{
|
||||||
|
$routeWithoutClosingOptionals = rtrim($route, ']');
|
||||||
|
$numOptionals = strlen($route) - strlen($routeWithoutClosingOptionals);
|
||||||
|
|
||||||
|
// Split on [ while skipping placeholders
|
||||||
|
$segments = preg_split('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \[~x', $routeWithoutClosingOptionals);
|
||||||
|
if ($numOptionals !== count($segments) - 1) {
|
||||||
|
// If there are any ] in the middle of the route, throw a more specific error message
|
||||||
|
if (preg_match('~' . self::VARIABLE_REGEX . '(*SKIP)(*F) | \]~x', $routeWithoutClosingOptionals)) {
|
||||||
|
throw new BadRouteException('Optional segments can only occur at the end of a route');
|
||||||
|
}
|
||||||
|
throw new BadRouteException("Number of opening '[' and closing ']' does not match");
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentRoute = '';
|
||||||
|
$routeDatas = [];
|
||||||
|
foreach ($segments as $n => $segment) {
|
||||||
|
if ($segment === '' && $n !== 0) {
|
||||||
|
throw new BadRouteException('Empty optional part');
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentRoute .= $segment;
|
||||||
|
$routeDatas[] = $this->parsePlaceholders($currentRoute);
|
||||||
|
}
|
||||||
|
return $routeDatas;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a route string that does not contain optional segments.
|
||||||
|
*
|
||||||
|
* @param string
|
||||||
|
* @return mixed[]
|
||||||
|
*/
|
||||||
|
private function parsePlaceholders($route)
|
||||||
|
{
|
||||||
|
if (!preg_match_all(
|
||||||
|
'~' . self::VARIABLE_REGEX . '~x', $route, $matches,
|
||||||
|
PREG_OFFSET_CAPTURE | PREG_SET_ORDER
|
||||||
|
)) {
|
||||||
|
return [$route];
|
||||||
|
}
|
||||||
|
|
||||||
|
$offset = 0;
|
||||||
|
$routeData = [];
|
||||||
|
foreach ($matches as $set) {
|
||||||
|
if ($set[0][1] > $offset) {
|
||||||
|
$routeData[] = substr($route, $offset, $set[0][1] - $offset);
|
||||||
|
}
|
||||||
|
$routeData[] = [
|
||||||
|
$set[1][0],
|
||||||
|
isset($set[2]) ? trim($set[2][0]) : self::DEFAULT_DISPATCH_REGEX
|
||||||
|
];
|
||||||
|
$offset = $set[0][1] + strlen($set[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($offset !== strlen($route)) {
|
||||||
|
$routeData[] = substr($route, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $routeData;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
api/vendor/nikic/fast-route/src/bootstrap.php
vendored
Normal file
12
api/vendor/nikic/fast-route/src/bootstrap.php
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
require __DIR__ . '/functions.php';
|
||||||
|
|
||||||
|
spl_autoload_register(function ($class) {
|
||||||
|
if (strpos($class, 'FastRoute\\') === 0) {
|
||||||
|
$name = substr($class, strlen('FastRoute'));
|
||||||
|
require __DIR__ . strtr($name, '\\', DIRECTORY_SEPARATOR) . '.php';
|
||||||
|
}
|
||||||
|
});
|
||||||
74
api/vendor/nikic/fast-route/src/functions.php
vendored
Normal file
74
api/vendor/nikic/fast-route/src/functions.php
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
if (!function_exists('FastRoute\simpleDispatcher')) {
|
||||||
|
/**
|
||||||
|
* @param callable $routeDefinitionCallback
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @return Dispatcher
|
||||||
|
*/
|
||||||
|
function simpleDispatcher(callable $routeDefinitionCallback, array $options = [])
|
||||||
|
{
|
||||||
|
$options += [
|
||||||
|
'routeParser' => 'FastRoute\\RouteParser\\Std',
|
||||||
|
'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased',
|
||||||
|
'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased',
|
||||||
|
'routeCollector' => 'FastRoute\\RouteCollector',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var RouteCollector $routeCollector */
|
||||||
|
$routeCollector = new $options['routeCollector'](
|
||||||
|
new $options['routeParser'], new $options['dataGenerator']
|
||||||
|
);
|
||||||
|
$routeDefinitionCallback($routeCollector);
|
||||||
|
|
||||||
|
return new $options['dispatcher']($routeCollector->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callable $routeDefinitionCallback
|
||||||
|
* @param array $options
|
||||||
|
*
|
||||||
|
* @return Dispatcher
|
||||||
|
*/
|
||||||
|
function cachedDispatcher(callable $routeDefinitionCallback, array $options = [])
|
||||||
|
{
|
||||||
|
$options += [
|
||||||
|
'routeParser' => 'FastRoute\\RouteParser\\Std',
|
||||||
|
'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased',
|
||||||
|
'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased',
|
||||||
|
'routeCollector' => 'FastRoute\\RouteCollector',
|
||||||
|
'cacheDisabled' => false,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!isset($options['cacheFile'])) {
|
||||||
|
throw new \LogicException('Must specify "cacheFile" option');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$options['cacheDisabled'] && file_exists($options['cacheFile'])) {
|
||||||
|
$dispatchData = require $options['cacheFile'];
|
||||||
|
if (!is_array($dispatchData)) {
|
||||||
|
throw new \RuntimeException('Invalid cache file "' . $options['cacheFile'] . '"');
|
||||||
|
}
|
||||||
|
return new $options['dispatcher']($dispatchData);
|
||||||
|
}
|
||||||
|
|
||||||
|
$routeCollector = new $options['routeCollector'](
|
||||||
|
new $options['routeParser'], new $options['dataGenerator']
|
||||||
|
);
|
||||||
|
$routeDefinitionCallback($routeCollector);
|
||||||
|
|
||||||
|
/** @var RouteCollector $routeCollector */
|
||||||
|
$dispatchData = $routeCollector->getData();
|
||||||
|
if (!$options['cacheDisabled']) {
|
||||||
|
file_put_contents(
|
||||||
|
$options['cacheFile'],
|
||||||
|
'<?php return ' . var_export($dispatchData, true) . ';'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new $options['dispatcher']($dispatchData);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
api/vendor/nikic/fast-route/test/Dispatcher/CharCountBasedTest.php
vendored
Normal file
16
api/vendor/nikic/fast-route/test/Dispatcher/CharCountBasedTest.php
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
class CharCountBasedTest extends DispatcherTest
|
||||||
|
{
|
||||||
|
protected function getDispatcherClass()
|
||||||
|
{
|
||||||
|
return 'FastRoute\\Dispatcher\\CharCountBased';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDataGeneratorClass()
|
||||||
|
{
|
||||||
|
return 'FastRoute\\DataGenerator\\CharCountBased';
|
||||||
|
}
|
||||||
|
}
|
||||||
581
api/vendor/nikic/fast-route/test/Dispatcher/DispatcherTest.php
vendored
Normal file
581
api/vendor/nikic/fast-route/test/Dispatcher/DispatcherTest.php
vendored
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
use FastRoute\RouteCollector;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
abstract class DispatcherTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Delegate dispatcher selection to child test classes
|
||||||
|
*/
|
||||||
|
abstract protected function getDispatcherClass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegate dataGenerator selection to child test classes
|
||||||
|
*/
|
||||||
|
abstract protected function getDataGeneratorClass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set appropriate options for the specific Dispatcher class we're testing
|
||||||
|
*/
|
||||||
|
private function generateDispatcherOptions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'dataGenerator' => $this->getDataGeneratorClass(),
|
||||||
|
'dispatcher' => $this->getDispatcherClass()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideFoundDispatchCases
|
||||||
|
*/
|
||||||
|
public function testFoundDispatches($method, $uri, $callback, $handler, $argDict)
|
||||||
|
{
|
||||||
|
$dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions());
|
||||||
|
$info = $dispatcher->dispatch($method, $uri);
|
||||||
|
$this->assertSame($dispatcher::FOUND, $info[0]);
|
||||||
|
$this->assertSame($handler, $info[1]);
|
||||||
|
$this->assertSame($argDict, $info[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideNotFoundDispatchCases
|
||||||
|
*/
|
||||||
|
public function testNotFoundDispatches($method, $uri, $callback)
|
||||||
|
{
|
||||||
|
$dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions());
|
||||||
|
$routeInfo = $dispatcher->dispatch($method, $uri);
|
||||||
|
$this->assertArrayNotHasKey(1, $routeInfo,
|
||||||
|
'NOT_FOUND result must only contain a single element in the returned info array'
|
||||||
|
);
|
||||||
|
$this->assertSame($dispatcher::NOT_FOUND, $routeInfo[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideMethodNotAllowedDispatchCases
|
||||||
|
*/
|
||||||
|
public function testMethodNotAllowedDispatches($method, $uri, $callback, $availableMethods)
|
||||||
|
{
|
||||||
|
$dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions());
|
||||||
|
$routeInfo = $dispatcher->dispatch($method, $uri);
|
||||||
|
$this->assertArrayHasKey(1, $routeInfo,
|
||||||
|
'METHOD_NOT_ALLOWED result must return an array of allowed methods at index 1'
|
||||||
|
);
|
||||||
|
|
||||||
|
list($routedStatus, $methodArray) = $dispatcher->dispatch($method, $uri);
|
||||||
|
$this->assertSame($dispatcher::METHOD_NOT_ALLOWED, $routedStatus);
|
||||||
|
$this->assertSame($availableMethods, $methodArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \FastRoute\BadRouteException
|
||||||
|
* @expectedExceptionMessage Cannot use the same placeholder "test" twice
|
||||||
|
*/
|
||||||
|
public function testDuplicateVariableNameError()
|
||||||
|
{
|
||||||
|
\FastRoute\simpleDispatcher(function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/foo/{test}/{test:\d+}', 'handler0');
|
||||||
|
}, $this->generateDispatcherOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \FastRoute\BadRouteException
|
||||||
|
* @expectedExceptionMessage Cannot register two routes matching "/user/([^/]+)" for method "GET"
|
||||||
|
*/
|
||||||
|
public function testDuplicateVariableRoute()
|
||||||
|
{
|
||||||
|
\FastRoute\simpleDispatcher(function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{id}', 'handler0'); // oops, forgot \d+ restriction ;)
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler1');
|
||||||
|
}, $this->generateDispatcherOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \FastRoute\BadRouteException
|
||||||
|
* @expectedExceptionMessage Cannot register two routes matching "/user" for method "GET"
|
||||||
|
*/
|
||||||
|
public function testDuplicateStaticRoute()
|
||||||
|
{
|
||||||
|
\FastRoute\simpleDispatcher(function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user', 'handler0');
|
||||||
|
$r->addRoute('GET', '/user', 'handler1');
|
||||||
|
}, $this->generateDispatcherOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \FastRoute\BadRouteException
|
||||||
|
* @expectedExceptionMessage Static route "/user/nikic" is shadowed by previously defined variable route "/user/([^/]+)" for method "GET"
|
||||||
|
*/
|
||||||
|
public function testShadowedStaticRoute()
|
||||||
|
{
|
||||||
|
\FastRoute\simpleDispatcher(function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler0');
|
||||||
|
$r->addRoute('GET', '/user/nikic', 'handler1');
|
||||||
|
}, $this->generateDispatcherOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \FastRoute\BadRouteException
|
||||||
|
* @expectedExceptionMessage Regex "(en|de)" for parameter "lang" contains a capturing group
|
||||||
|
*/
|
||||||
|
public function testCapturing()
|
||||||
|
{
|
||||||
|
\FastRoute\simpleDispatcher(function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/{lang:(en|de)}', 'handler0');
|
||||||
|
}, $this->generateDispatcherOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideFoundDispatchCases()
|
||||||
|
{
|
||||||
|
$cases = [];
|
||||||
|
|
||||||
|
// 0 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/resource/123/456', 'handler0');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/resource/123/456';
|
||||||
|
$handler = 'handler0';
|
||||||
|
$argDict = [];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 1 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/handler0', 'handler0');
|
||||||
|
$r->addRoute('GET', '/handler1', 'handler1');
|
||||||
|
$r->addRoute('GET', '/handler2', 'handler2');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/handler2';
|
||||||
|
$handler = 'handler2';
|
||||||
|
$argDict = [];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 2 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
|
||||||
|
$r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler2');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/user/rdlowrey';
|
||||||
|
$handler = 'handler2';
|
||||||
|
$argDict = ['name' => 'rdlowrey'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 3 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
// reuse $callback from #2
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/user/12345';
|
||||||
|
$handler = 'handler1';
|
||||||
|
$argDict = ['id' => '12345'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 4 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
// reuse $callback from #3
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/user/NaN';
|
||||||
|
$handler = 'handler2';
|
||||||
|
$argDict = ['name' => 'NaN'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 5 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
// reuse $callback from #4
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/user/rdlowrey/12345';
|
||||||
|
$handler = 'handler0';
|
||||||
|
$argDict = ['name' => 'rdlowrey', 'id' => '12345'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 6 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{id:[0-9]+}', 'handler0');
|
||||||
|
$r->addRoute('GET', '/user/12345/extension', 'handler1');
|
||||||
|
$r->addRoute('GET', '/user/{id:[0-9]+}.{extension}', 'handler2');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/user/12345.svg';
|
||||||
|
$handler = 'handler2';
|
||||||
|
$argDict = ['id' => '12345', 'extension' => 'svg'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 7 ----- Test GET method fallback on HEAD route miss ------------------------------------>
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler0');
|
||||||
|
$r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler1');
|
||||||
|
$r->addRoute('GET', '/static0', 'handler2');
|
||||||
|
$r->addRoute('GET', '/static1', 'handler3');
|
||||||
|
$r->addRoute('HEAD', '/static1', 'handler4');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'HEAD';
|
||||||
|
$uri = '/user/rdlowrey';
|
||||||
|
$handler = 'handler0';
|
||||||
|
$argDict = ['name' => 'rdlowrey'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 8 ----- Test GET method fallback on HEAD route miss ------------------------------------>
|
||||||
|
|
||||||
|
// reuse $callback from #7
|
||||||
|
|
||||||
|
$method = 'HEAD';
|
||||||
|
$uri = '/user/rdlowrey/1234';
|
||||||
|
$handler = 'handler1';
|
||||||
|
$argDict = ['name' => 'rdlowrey', 'id' => '1234'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 9 ----- Test GET method fallback on HEAD route miss ------------------------------------>
|
||||||
|
|
||||||
|
// reuse $callback from #8
|
||||||
|
|
||||||
|
$method = 'HEAD';
|
||||||
|
$uri = '/static0';
|
||||||
|
$handler = 'handler2';
|
||||||
|
$argDict = [];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 10 ---- Test existing HEAD route used if available (no fallback) ----------------------->
|
||||||
|
|
||||||
|
// reuse $callback from #9
|
||||||
|
|
||||||
|
$method = 'HEAD';
|
||||||
|
$uri = '/static1';
|
||||||
|
$handler = 'handler4';
|
||||||
|
$argDict = [];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 11 ---- More specified routes are not shadowed by less specific of another method ------>
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler0');
|
||||||
|
$r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'POST';
|
||||||
|
$uri = '/user/rdlowrey';
|
||||||
|
$handler = 'handler1';
|
||||||
|
$argDict = ['name' => 'rdlowrey'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 12 ---- Handler of more specific routes is used, if it occurs first -------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler0');
|
||||||
|
$r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1');
|
||||||
|
$r->addRoute('POST', '/user/{name}', 'handler2');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'POST';
|
||||||
|
$uri = '/user/rdlowrey';
|
||||||
|
$handler = 'handler1';
|
||||||
|
$argDict = ['name' => 'rdlowrey'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 13 ---- Route with constant suffix ----------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler0');
|
||||||
|
$r->addRoute('GET', '/user/{name}/edit', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/user/rdlowrey/edit';
|
||||||
|
$handler = 'handler1';
|
||||||
|
$argDict = ['name' => 'rdlowrey'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $handler, $argDict];
|
||||||
|
|
||||||
|
// 14 ---- Handle multiple methods with the same handler ---------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute(['GET', 'POST'], '/user', 'handlerGetPost');
|
||||||
|
$r->addRoute(['DELETE'], '/user', 'handlerDelete');
|
||||||
|
$r->addRoute([], '/user', 'handlerNone');
|
||||||
|
};
|
||||||
|
|
||||||
|
$argDict = [];
|
||||||
|
$cases[] = ['GET', '/user', $callback, 'handlerGetPost', $argDict];
|
||||||
|
$cases[] = ['POST', '/user', $callback, 'handlerGetPost', $argDict];
|
||||||
|
$cases[] = ['DELETE', '/user', $callback, 'handlerDelete', $argDict];
|
||||||
|
|
||||||
|
// 17 ----
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('POST', '/user.json', 'handler0');
|
||||||
|
$r->addRoute('GET', '/{entity}.json', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['GET', '/user.json', $callback, 'handler1', ['entity' => 'user']];
|
||||||
|
|
||||||
|
// 18 ----
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '', 'handler0');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['GET', '', $callback, 'handler0', []];
|
||||||
|
|
||||||
|
// 19 ----
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('HEAD', '/a/{foo}', 'handler0');
|
||||||
|
$r->addRoute('GET', '/b/{foo}', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['HEAD', '/b/bar', $callback, 'handler1', ['foo' => 'bar']];
|
||||||
|
|
||||||
|
// 20 ----
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('HEAD', '/a', 'handler0');
|
||||||
|
$r->addRoute('GET', '/b', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['HEAD', '/b', $callback, 'handler1', []];
|
||||||
|
|
||||||
|
// 21 ----
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/foo', 'handler0');
|
||||||
|
$r->addRoute('HEAD', '/{bar}', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['HEAD', '/foo', $callback, 'handler1', ['bar' => 'foo']];
|
||||||
|
|
||||||
|
// 22 ----
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('*', '/user', 'handler0');
|
||||||
|
$r->addRoute('*', '/{user}', 'handler1');
|
||||||
|
$r->addRoute('GET', '/user', 'handler2');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['GET', '/user', $callback, 'handler2', []];
|
||||||
|
|
||||||
|
// 23 ----
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('*', '/user', 'handler0');
|
||||||
|
$r->addRoute('GET', '/user', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['POST', '/user', $callback, 'handler0', []];
|
||||||
|
|
||||||
|
// 24 ----
|
||||||
|
|
||||||
|
$cases[] = ['HEAD', '/user', $callback, 'handler1', []];
|
||||||
|
|
||||||
|
// 25 ----
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/{bar}', 'handler0');
|
||||||
|
$r->addRoute('*', '/foo', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['GET', '/foo', $callback, 'handler0', ['bar' => 'foo']];
|
||||||
|
|
||||||
|
// 26 ----
|
||||||
|
|
||||||
|
$callback = function(RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user', 'handler0');
|
||||||
|
$r->addRoute('*', '/{foo:.*}', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['POST', '/bar', $callback, 'handler1', ['foo' => 'bar']];
|
||||||
|
|
||||||
|
// x -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
return $cases;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideNotFoundDispatchCases()
|
||||||
|
{
|
||||||
|
$cases = [];
|
||||||
|
|
||||||
|
// 0 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/resource/123/456', 'handler0');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/not-found';
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback];
|
||||||
|
|
||||||
|
// 1 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
// reuse callback from #0
|
||||||
|
$method = 'POST';
|
||||||
|
$uri = '/not-found';
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback];
|
||||||
|
|
||||||
|
// 2 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
// reuse callback from #1
|
||||||
|
$method = 'PUT';
|
||||||
|
$uri = '/not-found';
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback];
|
||||||
|
|
||||||
|
// 3 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/handler0', 'handler0');
|
||||||
|
$r->addRoute('GET', '/handler1', 'handler1');
|
||||||
|
$r->addRoute('GET', '/handler2', 'handler2');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/not-found';
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback];
|
||||||
|
|
||||||
|
// 4 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
|
||||||
|
$r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');
|
||||||
|
$r->addRoute('GET', '/user/{name}', 'handler2');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/not-found';
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback];
|
||||||
|
|
||||||
|
// 5 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
// reuse callback from #4
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/user/rdlowrey/12345/not-found';
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback];
|
||||||
|
|
||||||
|
// 6 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
// reuse callback from #5
|
||||||
|
$method = 'HEAD';
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback];
|
||||||
|
|
||||||
|
// x -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
return $cases;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideMethodNotAllowedDispatchCases()
|
||||||
|
{
|
||||||
|
$cases = [];
|
||||||
|
|
||||||
|
// 0 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/resource/123/456', 'handler0');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'POST';
|
||||||
|
$uri = '/resource/123/456';
|
||||||
|
$allowedMethods = ['GET'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $allowedMethods];
|
||||||
|
|
||||||
|
// 1 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/resource/123/456', 'handler0');
|
||||||
|
$r->addRoute('POST', '/resource/123/456', 'handler1');
|
||||||
|
$r->addRoute('PUT', '/resource/123/456', 'handler2');
|
||||||
|
$r->addRoute('*', '/', 'handler3');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'DELETE';
|
||||||
|
$uri = '/resource/123/456';
|
||||||
|
$allowedMethods = ['GET', 'POST', 'PUT'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $allowedMethods];
|
||||||
|
|
||||||
|
// 2 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
|
||||||
|
$r->addRoute('POST', '/user/{name}/{id:[0-9]+}', 'handler1');
|
||||||
|
$r->addRoute('PUT', '/user/{name}/{id:[0-9]+}', 'handler2');
|
||||||
|
$r->addRoute('PATCH', '/user/{name}/{id:[0-9]+}', 'handler3');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'DELETE';
|
||||||
|
$uri = '/user/rdlowrey/42';
|
||||||
|
$allowedMethods = ['GET', 'POST', 'PUT', 'PATCH'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $allowedMethods];
|
||||||
|
|
||||||
|
// 3 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('POST', '/user/{name}', 'handler1');
|
||||||
|
$r->addRoute('PUT', '/user/{name:[a-z]+}', 'handler2');
|
||||||
|
$r->addRoute('PATCH', '/user/{name:[a-z]+}', 'handler3');
|
||||||
|
};
|
||||||
|
|
||||||
|
$method = 'GET';
|
||||||
|
$uri = '/user/rdlowrey';
|
||||||
|
$allowedMethods = ['POST', 'PUT', 'PATCH'];
|
||||||
|
|
||||||
|
$cases[] = [$method, $uri, $callback, $allowedMethods];
|
||||||
|
|
||||||
|
// 4 -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute(['GET', 'POST'], '/user', 'handlerGetPost');
|
||||||
|
$r->addRoute(['DELETE'], '/user', 'handlerDelete');
|
||||||
|
$r->addRoute([], '/user', 'handlerNone');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['PUT', '/user', $callback, ['GET', 'POST', 'DELETE']];
|
||||||
|
|
||||||
|
// 5
|
||||||
|
|
||||||
|
$callback = function (RouteCollector $r) {
|
||||||
|
$r->addRoute('POST', '/user.json', 'handler0');
|
||||||
|
$r->addRoute('GET', '/{entity}.json', 'handler1');
|
||||||
|
};
|
||||||
|
|
||||||
|
$cases[] = ['PUT', '/user.json', $callback, ['POST', 'GET']];
|
||||||
|
|
||||||
|
// x -------------------------------------------------------------------------------------->
|
||||||
|
|
||||||
|
return $cases;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
api/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php
vendored
Normal file
16
api/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
class GroupCountBasedTest extends DispatcherTest
|
||||||
|
{
|
||||||
|
protected function getDispatcherClass()
|
||||||
|
{
|
||||||
|
return 'FastRoute\\Dispatcher\\GroupCountBased';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDataGeneratorClass()
|
||||||
|
{
|
||||||
|
return 'FastRoute\\DataGenerator\\GroupCountBased';
|
||||||
|
}
|
||||||
|
}
|
||||||
16
api/vendor/nikic/fast-route/test/Dispatcher/GroupPosBasedTest.php
vendored
Normal file
16
api/vendor/nikic/fast-route/test/Dispatcher/GroupPosBasedTest.php
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
class GroupPosBasedTest extends DispatcherTest
|
||||||
|
{
|
||||||
|
protected function getDispatcherClass()
|
||||||
|
{
|
||||||
|
return 'FastRoute\\Dispatcher\\GroupPosBased';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDataGeneratorClass()
|
||||||
|
{
|
||||||
|
return 'FastRoute\\DataGenerator\\GroupPosBased';
|
||||||
|
}
|
||||||
|
}
|
||||||
24
api/vendor/nikic/fast-route/test/Dispatcher/MarkBasedTest.php
vendored
Normal file
24
api/vendor/nikic/fast-route/test/Dispatcher/MarkBasedTest.php
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\Dispatcher;
|
||||||
|
|
||||||
|
class MarkBasedTest extends DispatcherTest
|
||||||
|
{
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
preg_match('/(*MARK:A)a/', 'a', $matches);
|
||||||
|
if (!isset($matches['MARK'])) {
|
||||||
|
$this->markTestSkipped('PHP 5.6 required for MARK support');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDispatcherClass()
|
||||||
|
{
|
||||||
|
return 'FastRoute\\Dispatcher\\MarkBased';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDataGeneratorClass()
|
||||||
|
{
|
||||||
|
return 'FastRoute\\DataGenerator\\MarkBased';
|
||||||
|
}
|
||||||
|
}
|
||||||
44
api/vendor/nikic/fast-route/test/HackTypechecker/HackTypecheckerTest.php
vendored
Normal file
44
api/vendor/nikic/fast-route/test/HackTypechecker/HackTypecheckerTest.php
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class HackTypecheckerTest extends TestCase
|
||||||
|
{
|
||||||
|
const SERVER_ALREADY_RUNNING_CODE = 77;
|
||||||
|
|
||||||
|
public function testTypechecks($recurse = true)
|
||||||
|
{
|
||||||
|
if (!defined('HHVM_VERSION')) {
|
||||||
|
$this->markTestSkipped('HHVM only');
|
||||||
|
}
|
||||||
|
if (!version_compare(HHVM_VERSION, '3.9.0', '>=')) {
|
||||||
|
$this->markTestSkipped('classname<T> requires HHVM 3.9+');
|
||||||
|
}
|
||||||
|
|
||||||
|
// The typechecker recurses the whole tree, so it makes sure
|
||||||
|
// that everything in fixtures/ is valid when this runs.
|
||||||
|
|
||||||
|
$output = [];
|
||||||
|
$exit_code = null;
|
||||||
|
exec(
|
||||||
|
'hh_server --check ' . escapeshellarg(__DIR__ . '/../../') . ' 2>&1',
|
||||||
|
$output,
|
||||||
|
$exit_code
|
||||||
|
);
|
||||||
|
if ($exit_code === self::SERVER_ALREADY_RUNNING_CODE) {
|
||||||
|
$this->assertTrue(
|
||||||
|
$recurse,
|
||||||
|
'Typechecker still running after running hh_client stop'
|
||||||
|
);
|
||||||
|
// Server already running - 3.10 => 3.11 regression:
|
||||||
|
// https://github.com/facebook/hhvm/issues/6646
|
||||||
|
exec('hh_client stop 2>/dev/null');
|
||||||
|
$this->testTypechecks(/* recurse = */ false);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
$this->assertSame(0, $exit_code, implode("\n", $output));
|
||||||
|
}
|
||||||
|
}
|
||||||
29
api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php
vendored
Normal file
29
api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?hh
|
||||||
|
|
||||||
|
namespace FastRoute\TestFixtures;
|
||||||
|
|
||||||
|
function all_options_simple(): \FastRoute\Dispatcher {
|
||||||
|
return \FastRoute\simpleDispatcher(
|
||||||
|
$collector ==> {},
|
||||||
|
shape(
|
||||||
|
'routeParser' => \FastRoute\RouteParser\Std::class,
|
||||||
|
'dataGenerator' => \FastRoute\DataGenerator\GroupCountBased::class,
|
||||||
|
'dispatcher' => \FastRoute\Dispatcher\GroupCountBased::class,
|
||||||
|
'routeCollector' => \FastRoute\RouteCollector::class,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function all_options_cached(): \FastRoute\Dispatcher {
|
||||||
|
return \FastRoute\cachedDispatcher(
|
||||||
|
$collector ==> {},
|
||||||
|
shape(
|
||||||
|
'routeParser' => \FastRoute\RouteParser\Std::class,
|
||||||
|
'dataGenerator' => \FastRoute\DataGenerator\GroupCountBased::class,
|
||||||
|
'dispatcher' => \FastRoute\Dispatcher\GroupCountBased::class,
|
||||||
|
'routeCollector' => \FastRoute\RouteCollector::class,
|
||||||
|
'cacheFile' => '/dev/null',
|
||||||
|
'cacheDisabled' => false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
11
api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php
vendored
Normal file
11
api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?hh
|
||||||
|
|
||||||
|
namespace FastRoute\TestFixtures;
|
||||||
|
|
||||||
|
function empty_options_simple(): \FastRoute\Dispatcher {
|
||||||
|
return \FastRoute\simpleDispatcher($collector ==> {}, shape());
|
||||||
|
}
|
||||||
|
|
||||||
|
function empty_options_cached(): \FastRoute\Dispatcher {
|
||||||
|
return \FastRoute\cachedDispatcher($collector ==> {}, shape());
|
||||||
|
}
|
||||||
11
api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php
vendored
Normal file
11
api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?hh
|
||||||
|
|
||||||
|
namespace FastRoute\TestFixtures;
|
||||||
|
|
||||||
|
function no_options_simple(): \FastRoute\Dispatcher {
|
||||||
|
return \FastRoute\simpleDispatcher($collector ==> {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function no_options_cached(): \FastRoute\Dispatcher {
|
||||||
|
return \FastRoute\cachedDispatcher($collector ==> {});
|
||||||
|
}
|
||||||
108
api/vendor/nikic/fast-route/test/RouteCollectorTest.php
vendored
Normal file
108
api/vendor/nikic/fast-route/test/RouteCollectorTest.php
vendored
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class RouteCollectorTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testShortcuts()
|
||||||
|
{
|
||||||
|
$r = new DummyRouteCollector();
|
||||||
|
|
||||||
|
$r->delete('/delete', 'delete');
|
||||||
|
$r->get('/get', 'get');
|
||||||
|
$r->head('/head', 'head');
|
||||||
|
$r->patch('/patch', 'patch');
|
||||||
|
$r->post('/post', 'post');
|
||||||
|
$r->put('/put', 'put');
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
['DELETE', '/delete', 'delete'],
|
||||||
|
['GET', '/get', 'get'],
|
||||||
|
['HEAD', '/head', 'head'],
|
||||||
|
['PATCH', '/patch', 'patch'],
|
||||||
|
['POST', '/post', 'post'],
|
||||||
|
['PUT', '/put', 'put'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertSame($expected, $r->routes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGroups()
|
||||||
|
{
|
||||||
|
$r = new DummyRouteCollector();
|
||||||
|
|
||||||
|
$r->delete('/delete', 'delete');
|
||||||
|
$r->get('/get', 'get');
|
||||||
|
$r->head('/head', 'head');
|
||||||
|
$r->patch('/patch', 'patch');
|
||||||
|
$r->post('/post', 'post');
|
||||||
|
$r->put('/put', 'put');
|
||||||
|
|
||||||
|
$r->addGroup('/group-one', function (DummyRouteCollector $r) {
|
||||||
|
$r->delete('/delete', 'delete');
|
||||||
|
$r->get('/get', 'get');
|
||||||
|
$r->head('/head', 'head');
|
||||||
|
$r->patch('/patch', 'patch');
|
||||||
|
$r->post('/post', 'post');
|
||||||
|
$r->put('/put', 'put');
|
||||||
|
|
||||||
|
$r->addGroup('/group-two', function (DummyRouteCollector $r) {
|
||||||
|
$r->delete('/delete', 'delete');
|
||||||
|
$r->get('/get', 'get');
|
||||||
|
$r->head('/head', 'head');
|
||||||
|
$r->patch('/patch', 'patch');
|
||||||
|
$r->post('/post', 'post');
|
||||||
|
$r->put('/put', 'put');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$r->addGroup('/admin', function (DummyRouteCollector $r) {
|
||||||
|
$r->get('-some-info', 'admin-some-info');
|
||||||
|
});
|
||||||
|
$r->addGroup('/admin-', function (DummyRouteCollector $r) {
|
||||||
|
$r->get('more-info', 'admin-more-info');
|
||||||
|
});
|
||||||
|
|
||||||
|
$expected = [
|
||||||
|
['DELETE', '/delete', 'delete'],
|
||||||
|
['GET', '/get', 'get'],
|
||||||
|
['HEAD', '/head', 'head'],
|
||||||
|
['PATCH', '/patch', 'patch'],
|
||||||
|
['POST', '/post', 'post'],
|
||||||
|
['PUT', '/put', 'put'],
|
||||||
|
['DELETE', '/group-one/delete', 'delete'],
|
||||||
|
['GET', '/group-one/get', 'get'],
|
||||||
|
['HEAD', '/group-one/head', 'head'],
|
||||||
|
['PATCH', '/group-one/patch', 'patch'],
|
||||||
|
['POST', '/group-one/post', 'post'],
|
||||||
|
['PUT', '/group-one/put', 'put'],
|
||||||
|
['DELETE', '/group-one/group-two/delete', 'delete'],
|
||||||
|
['GET', '/group-one/group-two/get', 'get'],
|
||||||
|
['HEAD', '/group-one/group-two/head', 'head'],
|
||||||
|
['PATCH', '/group-one/group-two/patch', 'patch'],
|
||||||
|
['POST', '/group-one/group-two/post', 'post'],
|
||||||
|
['PUT', '/group-one/group-two/put', 'put'],
|
||||||
|
['GET', '/admin-some-info', 'admin-some-info'],
|
||||||
|
['GET', '/admin-more-info', 'admin-more-info'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertSame($expected, $r->routes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DummyRouteCollector extends RouteCollector
|
||||||
|
{
|
||||||
|
public $routes = [];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addRoute($method, $route, $handler)
|
||||||
|
{
|
||||||
|
$route = $this->currentGroupPrefix . $route;
|
||||||
|
$this->routes[] = [$method, $route, $handler];
|
||||||
|
}
|
||||||
|
}
|
||||||
154
api/vendor/nikic/fast-route/test/RouteParser/StdTest.php
vendored
Normal file
154
api/vendor/nikic/fast-route/test/RouteParser/StdTest.php
vendored
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace FastRoute\RouteParser;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class StdTest extends TestCase
|
||||||
|
{
|
||||||
|
/** @dataProvider provideTestParse */
|
||||||
|
public function testParse($routeString, $expectedRouteDatas)
|
||||||
|
{
|
||||||
|
$parser = new Std();
|
||||||
|
$routeDatas = $parser->parse($routeString);
|
||||||
|
$this->assertSame($expectedRouteDatas, $routeDatas);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @dataProvider provideTestParseError */
|
||||||
|
public function testParseError($routeString, $expectedExceptionMessage)
|
||||||
|
{
|
||||||
|
$parser = new Std();
|
||||||
|
$this->setExpectedException('FastRoute\\BadRouteException', $expectedExceptionMessage);
|
||||||
|
$parser->parse($routeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideTestParse()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'/test',
|
||||||
|
[
|
||||||
|
['/test'],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test/{param}',
|
||||||
|
[
|
||||||
|
['/test/', ['param', '[^/]+']],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/te{ param }st',
|
||||||
|
[
|
||||||
|
['/te', ['param', '[^/]+'], 'st']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test/{param1}/test2/{param2}',
|
||||||
|
[
|
||||||
|
['/test/', ['param1', '[^/]+'], '/test2/', ['param2', '[^/]+']]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test/{param:\d+}',
|
||||||
|
[
|
||||||
|
['/test/', ['param', '\d+']]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test/{ param : \d{1,9} }',
|
||||||
|
[
|
||||||
|
['/test/', ['param', '\d{1,9}']]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test[opt]',
|
||||||
|
[
|
||||||
|
['/test'],
|
||||||
|
['/testopt'],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test[/{param}]',
|
||||||
|
[
|
||||||
|
['/test'],
|
||||||
|
['/test/', ['param', '[^/]+']],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/{param}[opt]',
|
||||||
|
[
|
||||||
|
['/', ['param', '[^/]+']],
|
||||||
|
['/', ['param', '[^/]+'], 'opt']
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test[/{name}[/{id:[0-9]+}]]',
|
||||||
|
[
|
||||||
|
['/test'],
|
||||||
|
['/test/', ['name', '[^/]+']],
|
||||||
|
['/test/', ['name', '[^/]+'], '/', ['id', '[0-9]+']],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'',
|
||||||
|
[
|
||||||
|
[''],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'[test]',
|
||||||
|
[
|
||||||
|
[''],
|
||||||
|
['test'],
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/{foo-bar}',
|
||||||
|
[
|
||||||
|
['/', ['foo-bar', '[^/]+']]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/{_foo:.*}',
|
||||||
|
[
|
||||||
|
['/', ['_foo', '.*']]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideTestParseError()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'/test[opt',
|
||||||
|
"Number of opening '[' and closing ']' does not match"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test[opt[opt2]',
|
||||||
|
"Number of opening '[' and closing ']' does not match"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/testopt]',
|
||||||
|
"Number of opening '[' and closing ']' does not match"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test[]',
|
||||||
|
'Empty optional part'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test[[opt]]',
|
||||||
|
'Empty optional part'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'[[test]]',
|
||||||
|
'Empty optional part'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'/test[/opt]/required',
|
||||||
|
'Optional segments can only occur at the end of a route'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
11
api/vendor/nikic/fast-route/test/bootstrap.php
vendored
Normal file
11
api/vendor/nikic/fast-route/test/bootstrap.php
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../src/functions.php';
|
||||||
|
|
||||||
|
spl_autoload_register(function ($class) {
|
||||||
|
if (strpos($class, 'FastRoute\\') === 0) {
|
||||||
|
$dir = strcasecmp(substr($class, -4), 'Test') ? 'src/' : 'test/';
|
||||||
|
$name = substr($class, strlen('FastRoute'));
|
||||||
|
require __DIR__ . '/../' . $dir . strtr($name, '\\', DIRECTORY_SEPARATOR) . '.php';
|
||||||
|
}
|
||||||
|
});
|
||||||
21
api/vendor/php-di/invoker/LICENSE
vendored
Normal file
21
api/vendor/php-di/invoker/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) Matthieu Napoli
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
234
api/vendor/php-di/invoker/README.md
vendored
Normal file
234
api/vendor/php-di/invoker/README.md
vendored
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
# Invoker
|
||||||
|
|
||||||
|
Generic and extensible callable invoker.
|
||||||
|
|
||||||
|
[](https://github.com/PHP-DI/Invoker/actions/workflows/ci.yml)
|
||||||
|
[](https://packagist.org/packages/PHP-DI/invoker)
|
||||||
|
[](https://packagist.org/packages/php-di/invoker)
|
||||||
|
|
||||||
|
## Why?
|
||||||
|
|
||||||
|
Who doesn't need an over-engineered `call_user_func()`?
|
||||||
|
|
||||||
|
### Named parameters
|
||||||
|
|
||||||
|
Does this [Silex](https://github.com/silexphp/Silex#readme) example look familiar:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$app->get('/project/{project}/issue/{issue}', function ($project, $issue) {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Or this command defined with [Silly](https://github.com/mnapoli/silly#usage):
|
||||||
|
|
||||||
|
```php
|
||||||
|
$app->command('greet [name] [--yell]', function ($name, $yell) {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Same pattern in [Slim](https://www.slimframework.com):
|
||||||
|
|
||||||
|
```php
|
||||||
|
$app->get('/hello/:name', function ($name) {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
You get the point. These frameworks invoke the controller/command/handler using something akin to named parameters: whatever the order of the parameters, they are matched by their name.
|
||||||
|
|
||||||
|
**This library allows to invoke callables with named parameters in a generic and extensible way.**
|
||||||
|
|
||||||
|
### Dependency injection
|
||||||
|
|
||||||
|
Anyone familiar with AngularJS is familiar with how dependency injection is performed:
|
||||||
|
|
||||||
|
```js
|
||||||
|
angular.controller('MyController', ['dep1', 'dep2', function(dep1, dep2) {
|
||||||
|
// ...
|
||||||
|
}]);
|
||||||
|
```
|
||||||
|
|
||||||
|
In PHP we find this pattern again in some frameworks and DI containers with partial to full support. For example in Silex you can type-hint the application to get it injected, but it only works with `Silex\Application`:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$app->get('/hello/{name}', function (Silex\Application $app, $name) {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
In Silly, it only works with `OutputInterface` to inject the application output:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$app->command('greet [name]', function ($name, OutputInterface $output) {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
[PHP-DI](https://php-di.org/doc/container.html) provides a way to invoke a callable and resolve all dependencies from the container using type-hints:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$container->call(function (Logger $logger, EntityManager $em) {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**This library provides clear extension points to let frameworks implement any kind of dependency injection support they want.**
|
||||||
|
|
||||||
|
### TL/DR
|
||||||
|
|
||||||
|
In short, this library is meant to be a base building block for calling a function with named parameters and/or dependency injection.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ composer require PHP-DI/invoker
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Default behavior
|
||||||
|
|
||||||
|
By default the `Invoker` can call using named parameters:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$invoker = new Invoker\Invoker;
|
||||||
|
|
||||||
|
$invoker->call(function () {
|
||||||
|
echo 'Hello world!';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Simple parameter array
|
||||||
|
$invoker->call(function ($name) {
|
||||||
|
echo 'Hello ' . $name;
|
||||||
|
}, ['John']);
|
||||||
|
|
||||||
|
// Named parameters
|
||||||
|
$invoker->call(function ($name) {
|
||||||
|
echo 'Hello ' . $name;
|
||||||
|
}, [
|
||||||
|
'name' => 'John'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Use the default value
|
||||||
|
$invoker->call(function ($name = 'world') {
|
||||||
|
echo 'Hello ' . $name;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Invoke any PHP callable
|
||||||
|
$invoker->call(['MyClass', 'myStaticMethod']);
|
||||||
|
|
||||||
|
// Using Class::method syntax
|
||||||
|
$invoker->call('MyClass::myStaticMethod');
|
||||||
|
```
|
||||||
|
|
||||||
|
Dependency injection in parameters is supported but needs to be configured with your container. Read on or jump to [*Built-in support for dependency injection*](#built-in-support-for-dependency-injection) if you are impatient.
|
||||||
|
|
||||||
|
Additionally, callables can also be resolved from your container. Read on or jump to [*Resolving callables from a container*](#resolving-callables-from-a-container) if you are impatient.
|
||||||
|
|
||||||
|
### Parameter resolvers
|
||||||
|
|
||||||
|
Extending the behavior of the `Invoker` is easy and is done by implementing a [`ParameterResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ParameterResolver.php).
|
||||||
|
|
||||||
|
This is explained in details the [Parameter resolvers documentation](doc/parameter-resolvers.md).
|
||||||
|
|
||||||
|
#### Built-in support for dependency injection
|
||||||
|
|
||||||
|
Rather than have you re-implement support for dependency injection with different containers every time, this package ships with 2 optional resolvers:
|
||||||
|
|
||||||
|
- [`TypeHintContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/TypeHintContainerResolver.php)
|
||||||
|
|
||||||
|
This resolver will inject container entries by searching for the class name using the type-hint:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$invoker->call(function (Psr\Logger\LoggerInterface $logger) {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example it will `->get('Psr\Logger\LoggerInterface')` from the container and inject it.
|
||||||
|
|
||||||
|
This resolver is only useful if you store objects in your container using the class (or interface) name. Silex or Symfony for example store services under a custom name (e.g. `twig`, `db`, etc.) instead of the class name: in that case use the resolver shown below.
|
||||||
|
|
||||||
|
- [`ParameterNameContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/ParameterNameContainerResolver.php)
|
||||||
|
|
||||||
|
This resolver will inject container entries by searching for the name of the parameter:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$invoker->call(function ($twig) {
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example it will `->get('twig')` from the container and inject it.
|
||||||
|
|
||||||
|
These resolvers can work with any dependency injection container compliant with [PSR-11](http://www.php-fig.org/psr/psr-11/).
|
||||||
|
|
||||||
|
Setting up those resolvers is simple:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// $container must be an instance of Psr\Container\ContainerInterface
|
||||||
|
$container = ...
|
||||||
|
|
||||||
|
$containerResolver = new TypeHintContainerResolver($container);
|
||||||
|
// or
|
||||||
|
$containerResolver = new ParameterNameContainerResolver($container);
|
||||||
|
|
||||||
|
$invoker = new Invoker\Invoker;
|
||||||
|
// Register it before all the other parameter resolvers
|
||||||
|
$invoker->getParameterResolver()->prependResolver($containerResolver);
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also register both resolvers at the same time if you wish by prepending both. Implementing support for more tricky things is easy and up to you!
|
||||||
|
|
||||||
|
### Resolving callables from a container
|
||||||
|
|
||||||
|
The `Invoker` can be wired to your DI container to resolve the callables.
|
||||||
|
|
||||||
|
For example with an invokable class:
|
||||||
|
|
||||||
|
```php
|
||||||
|
class MyHandler
|
||||||
|
{
|
||||||
|
public function __invoke()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default this doesn't work: an instance of the class should be provided
|
||||||
|
$invoker->call('MyHandler');
|
||||||
|
|
||||||
|
// If we set up the container to use
|
||||||
|
$invoker = new Invoker\Invoker(null, $container);
|
||||||
|
// Now 'MyHandler' is resolved using the container!
|
||||||
|
$invoker->call('MyHandler');
|
||||||
|
```
|
||||||
|
|
||||||
|
The same works for a class method:
|
||||||
|
|
||||||
|
```php
|
||||||
|
class WelcomeController
|
||||||
|
{
|
||||||
|
public function home()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// By default this doesn't work: home() is not a static method
|
||||||
|
$invoker->call(['WelcomeController', 'home']);
|
||||||
|
|
||||||
|
// If we set up the container to use
|
||||||
|
$invoker = new Invoker\Invoker(null, $container);
|
||||||
|
// Now 'WelcomeController' is resolved using the container!
|
||||||
|
$invoker->call(['WelcomeController', 'home']);
|
||||||
|
// Alternatively we can use the Class::method syntax
|
||||||
|
$invoker->call('WelcomeController::home');
|
||||||
|
```
|
||||||
|
|
||||||
|
That feature can be used as the base building block for a framework's dispatcher.
|
||||||
|
|
||||||
|
Again, any [PSR-11](https://www.php-fig.org/psr/psr-11/) compliant container can be provided.
|
||||||
|
|
||||||
32
api/vendor/php-di/invoker/composer.json
vendored
Normal file
32
api/vendor/php-di/invoker/composer.json
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "php-di/invoker",
|
||||||
|
"description": "Generic and extensible callable invoker",
|
||||||
|
"keywords": ["invoker", "dependency-injection", "dependency", "injection", "callable", "invoke"],
|
||||||
|
"homepage": "https://github.com/PHP-DI/Invoker",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Invoker\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Invoker\\Test\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.3",
|
||||||
|
"psr/container": "^1.0|^2.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^9.0 || ^10 || ^11 || ^12",
|
||||||
|
"athletic/athletic": "~0.1.8",
|
||||||
|
"mnapoli/hard-mode": "~0.3.0"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"dealerdirect/phpcodesniffer-composer-installer": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
124
api/vendor/php-di/invoker/src/CallableResolver.php
vendored
Normal file
124
api/vendor/php-di/invoker/src/CallableResolver.php
vendored
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Invoker;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Invoker\Exception\NotCallableException;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Psr\Container\NotFoundExceptionInterface;
|
||||||
|
use ReflectionException;
|
||||||
|
use ReflectionMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves a callable from a container.
|
||||||
|
*/
|
||||||
|
class CallableResolver
|
||||||
|
{
|
||||||
|
/** @var ContainerInterface */
|
||||||
|
private $container;
|
||||||
|
|
||||||
|
public function __construct(ContainerInterface $container)
|
||||||
|
{
|
||||||
|
$this->container = $container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the given callable into a real PHP callable.
|
||||||
|
*
|
||||||
|
* @param callable|string|array $callable
|
||||||
|
* @return callable Real PHP callable.
|
||||||
|
* @throws NotCallableException|ReflectionException
|
||||||
|
*/
|
||||||
|
public function resolve($callable): callable
|
||||||
|
{
|
||||||
|
if (is_string($callable) && strpos($callable, '::') !== false) {
|
||||||
|
$callable = explode('::', $callable, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
$callable = $this->resolveFromContainer($callable);
|
||||||
|
|
||||||
|
if (! is_callable($callable)) {
|
||||||
|
throw NotCallableException::fromInvalidCallable($callable, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callable|string|array $callable
|
||||||
|
* @return callable|mixed
|
||||||
|
* @throws NotCallableException|ReflectionException
|
||||||
|
*/
|
||||||
|
private function resolveFromContainer($callable)
|
||||||
|
{
|
||||||
|
// Shortcut for a very common use case
|
||||||
|
if ($callable instanceof Closure) {
|
||||||
|
return $callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's already a callable there is nothing to do
|
||||||
|
if (is_callable($callable)) {
|
||||||
|
// TODO with PHP 8 that should not be necessary to check this anymore
|
||||||
|
if (! $this->isStaticCallToNonStaticMethod($callable)) {
|
||||||
|
return $callable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The callable is a container entry name
|
||||||
|
if (is_string($callable)) {
|
||||||
|
try {
|
||||||
|
return $this->container->get($callable);
|
||||||
|
} catch (NotFoundExceptionInterface $e) {
|
||||||
|
if ($this->container->has($callable)) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
throw NotCallableException::fromInvalidCallable($callable, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The callable is an array whose first item is a container entry name
|
||||||
|
// e.g. ['some-container-entry', 'methodToCall']
|
||||||
|
if (is_array($callable) && is_string($callable[0])) {
|
||||||
|
try {
|
||||||
|
// Replace the container entry name by the actual object
|
||||||
|
$callable[0] = $this->container->get($callable[0]);
|
||||||
|
return $callable;
|
||||||
|
} catch (NotFoundExceptionInterface $e) {
|
||||||
|
if ($this->container->has($callable[0])) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
throw new NotCallableException(sprintf(
|
||||||
|
'Cannot call %s() on %s because it is not a class nor a valid container entry',
|
||||||
|
$callable[1],
|
||||||
|
$callable[0]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unrecognized stuff, we let it fail later
|
||||||
|
return $callable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the callable represents a static call to a non-static method.
|
||||||
|
*
|
||||||
|
* @param mixed $callable
|
||||||
|
* @throws ReflectionException
|
||||||
|
*/
|
||||||
|
private function isStaticCallToNonStaticMethod($callable): bool
|
||||||
|
{
|
||||||
|
if (is_array($callable) && is_string($callable[0])) {
|
||||||
|
[$class, $method] = $callable;
|
||||||
|
|
||||||
|
if (! method_exists($class, $method)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$reflection = new ReflectionMethod($class, $method);
|
||||||
|
|
||||||
|
return ! $reflection->isStatic();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
api/vendor/php-di/invoker/src/Exception/InvocationException.php
vendored
Normal file
10
api/vendor/php-di/invoker/src/Exception/InvocationException.php
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Invoker\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Impossible to invoke the callable.
|
||||||
|
*/
|
||||||
|
class InvocationException extends \Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
33
api/vendor/php-di/invoker/src/Exception/NotCallableException.php
vendored
Normal file
33
api/vendor/php-di/invoker/src/Exception/NotCallableException.php
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Invoker\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The given callable is not actually callable.
|
||||||
|
*/
|
||||||
|
class NotCallableException extends InvocationException
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param mixed $value
|
||||||
|
*/
|
||||||
|
public static function fromInvalidCallable($value, bool $containerEntry = false): self
|
||||||
|
{
|
||||||
|
if (is_object($value)) {
|
||||||
|
$message = sprintf('Instance of %s is not a callable', get_class($value));
|
||||||
|
} elseif (is_array($value) && isset($value[0], $value[1])) {
|
||||||
|
$class = is_object($value[0]) ? get_class($value[0]) : $value[0];
|
||||||
|
|
||||||
|
$extra = method_exists($class, '__call') || method_exists($class, '__callStatic')
|
||||||
|
? ' A __call() or __callStatic() method exists but magic methods are not supported.'
|
||||||
|
: '';
|
||||||
|
|
||||||
|
$message = sprintf('%s::%s() is not a callable.%s', $class, $value[1], $extra);
|
||||||
|
} elseif ($containerEntry) {
|
||||||
|
$message = var_export($value, true) . ' is neither a callable nor a valid container entry';
|
||||||
|
} else {
|
||||||
|
$message = var_export($value, true) . ' is not a callable';
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
api/vendor/php-di/invoker/src/Exception/NotEnoughParametersException.php
vendored
Normal file
10
api/vendor/php-di/invoker/src/Exception/NotEnoughParametersException.php
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Invoker\Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not enough parameters could be resolved to invoke the callable.
|
||||||
|
*/
|
||||||
|
class NotEnoughParametersException extends InvocationException
|
||||||
|
{
|
||||||
|
}
|
||||||
109
api/vendor/php-di/invoker/src/Invoker.php
vendored
Normal file
109
api/vendor/php-di/invoker/src/Invoker.php
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Invoker;
|
||||||
|
|
||||||
|
use Invoker\Exception\NotCallableException;
|
||||||
|
use Invoker\Exception\NotEnoughParametersException;
|
||||||
|
use Invoker\ParameterResolver\AssociativeArrayResolver;
|
||||||
|
use Invoker\ParameterResolver\DefaultValueResolver;
|
||||||
|
use Invoker\ParameterResolver\NumericArrayResolver;
|
||||||
|
use Invoker\ParameterResolver\ParameterResolver;
|
||||||
|
use Invoker\ParameterResolver\ResolverChain;
|
||||||
|
use Invoker\Reflection\CallableReflection;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use ReflectionParameter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke a callable.
|
||||||
|
*/
|
||||||
|
class Invoker implements InvokerInterface
|
||||||
|
{
|
||||||
|
/** @var CallableResolver|null */
|
||||||
|
private $callableResolver;
|
||||||
|
|
||||||
|
/** @var ParameterResolver */
|
||||||
|
private $parameterResolver;
|
||||||
|
|
||||||
|
/** @var ContainerInterface|null */
|
||||||
|
private $container;
|
||||||
|
|
||||||
|
public function __construct(?ParameterResolver $parameterResolver = null, ?ContainerInterface $container = null)
|
||||||
|
{
|
||||||
|
$this->parameterResolver = $parameterResolver ?: $this->createParameterResolver();
|
||||||
|
$this->container = $container;
|
||||||
|
|
||||||
|
if ($container) {
|
||||||
|
$this->callableResolver = new CallableResolver($container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function call($callable, array $parameters = [])
|
||||||
|
{
|
||||||
|
if ($this->callableResolver) {
|
||||||
|
$callable = $this->callableResolver->resolve($callable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! is_callable($callable)) {
|
||||||
|
throw new NotCallableException(sprintf(
|
||||||
|
'%s is not a callable',
|
||||||
|
is_object($callable) ? 'Instance of ' . get_class($callable) : var_export($callable, true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$callableReflection = CallableReflection::create($callable);
|
||||||
|
|
||||||
|
$args = $this->parameterResolver->getParameters($callableReflection, $parameters, []);
|
||||||
|
|
||||||
|
// Sort by array key because call_user_func_array ignores numeric keys
|
||||||
|
ksort($args);
|
||||||
|
|
||||||
|
// Check all parameters are resolved
|
||||||
|
$diff = array_diff_key($callableReflection->getParameters(), $args);
|
||||||
|
$parameter = reset($diff);
|
||||||
|
if ($parameter && \assert($parameter instanceof ReflectionParameter) && ! $parameter->isVariadic()) {
|
||||||
|
throw new NotEnoughParametersException(sprintf(
|
||||||
|
'Unable to invoke the callable because no value was given for parameter %d ($%s)',
|
||||||
|
$parameter->getPosition() + 1,
|
||||||
|
$parameter->name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return call_user_func_array($callable, $args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the default parameter resolver.
|
||||||
|
*/
|
||||||
|
private function createParameterResolver(): ParameterResolver
|
||||||
|
{
|
||||||
|
return new ResolverChain([
|
||||||
|
new NumericArrayResolver,
|
||||||
|
new AssociativeArrayResolver,
|
||||||
|
new DefaultValueResolver,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ParameterResolver By default it's a ResolverChain
|
||||||
|
*/
|
||||||
|
public function getParameterResolver(): ParameterResolver
|
||||||
|
{
|
||||||
|
return $this->parameterResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContainer(): ?ContainerInterface
|
||||||
|
{
|
||||||
|
return $this->container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return CallableResolver|null Returns null if no container was given in the constructor.
|
||||||
|
*/
|
||||||
|
public function getCallableResolver(): ?CallableResolver
|
||||||
|
{
|
||||||
|
return $this->callableResolver;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user