friendship ended with social-app. php is my new best friend

add sample db and db adapter; remove unused php packages

Changed files
+292 -13494
data
lib
templates
vendor
+1
.gitignore
···
.env.local
jwks.json
data/*.json
+
*.db
# caches
.eslintcache
-2
composer.json
···
"league/commonmark": "^2.7",
"monolog/monolog": "^3.9",
"chillerlan/php-oauth": "^1.0",
-
"tracy/tracy": "^2.10",
-
"flightphp/runway": "^1.1",
"fusonic/opengraph": "^3.0",
"react/promise": "^3.2",
"react/async": "^4.3"
+48 -245
composer.lock
···
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
-
"content-hash": "d1b9a49dbc0044c8b668ec563b93ed20",
+
"content-hash": "7ac28666d78b506521cc7fcc74a83cc0",
"packages": [
-
{
-
"name": "adhocore/cli",
-
"version": "v1.9.4",
-
"source": {
-
"type": "git",
-
"url": "https://github.com/adhocore/php-cli.git",
-
"reference": "474dc3d7ab139796be98b104d891476e3916b6f4"
-
},
-
"dist": {
-
"type": "zip",
-
"url": "https://api.github.com/repos/adhocore/php-cli/zipball/474dc3d7ab139796be98b104d891476e3916b6f4",
-
"reference": "474dc3d7ab139796be98b104d891476e3916b6f4",
-
"shasum": ""
-
},
-
"require": {
-
"php": ">=8.0"
-
},
-
"require-dev": {
-
"phpunit/phpunit": "^9.0"
-
},
-
"type": "library",
-
"autoload": {
-
"files": [
-
"src/functions.php"
-
],
-
"psr-4": {
-
"Ahc\\Cli\\": "src/"
-
}
-
},
-
"notification-url": "https://packagist.org/downloads/",
-
"license": [
-
"MIT"
-
],
-
"authors": [
-
{
-
"name": "Jitendra Adhikari",
-
"email": "jiten.adhikary@gmail.com"
-
}
-
],
-
"description": "Command line interface library for PHP",
-
"keywords": [
-
"argument-parser",
-
"argv-parser",
-
"cli",
-
"cli-action",
-
"cli-app",
-
"cli-color",
-
"cli-option",
-
"cli-writer",
-
"command",
-
"console",
-
"console-app",
-
"php-cli",
-
"php8",
-
"stream-input",
-
"stream-output"
-
],
-
"support": {
-
"issues": "https://github.com/adhocore/php-cli/issues",
-
"source": "https://github.com/adhocore/php-cli/tree/v1.9.4"
-
},
-
"funding": [
-
{
-
"url": "https://paypal.me/ji10",
-
"type": "custom"
-
},
-
{
-
"url": "https://github.com/adhocore",
-
"type": "github"
-
}
-
],
-
"time": "2025-05-11T13:23:54+00:00"
-
},
{
"name": "chillerlan/php-http-message-utils",
"version": "2.2.2",
···
"source": "https://github.com/flightphp/core/tree/v3.17.2"
},
"time": "2025-10-03T21:05:48+00:00"
-
},
-
{
-
"name": "flightphp/runway",
-
"version": "v1.1.2",
-
"source": {
-
"type": "git",
-
"url": "https://github.com/flightphp/runway.git",
-
"reference": "b88c1901b77eda935ef475af772445c3108cf23f"
-
},
-
"dist": {
-
"type": "zip",
-
"url": "https://api.github.com/repos/flightphp/runway/zipball/b88c1901b77eda935ef475af772445c3108cf23f",
-
"reference": "b88c1901b77eda935ef475af772445c3108cf23f",
-
"shasum": ""
-
},
-
"require": {
-
"adhocore/cli": "^1.7",
-
"nette/php-generator": "^4.1",
-
"php": "^8.2"
-
},
-
"require-dev": {
-
"phpstan/extension-installer": "^1.3",
-
"phpstan/phpstan": "^1.10",
-
"phpunit/phpunit": "^9.5",
-
"rregeer/phpunit-coverage-check": "^0.3.1",
-
"squizlabs/php_codesniffer": "^3.8"
-
},
-
"bin": [
-
"runway"
-
],
-
"type": "library",
-
"autoload": {
-
"psr-4": {
-
"flight\\": "src/"
-
}
-
},
-
"notification-url": "https://packagist.org/downloads/",
-
"license": [
-
"MIT"
-
],
-
"authors": [
-
{
-
"name": "n0nag0n",
-
"email": "n0nag0n@sky-9.com"
-
}
-
],
-
"description": "Console app for the Flight PHP Framework.",
-
"support": {
-
"issues": "https://github.com/flightphp/runway/issues",
-
"source": "https://github.com/flightphp/runway/tree/v1.1.2"
-
},
-
"time": "2025-01-11T17:52:47+00:00"
},
{
"name": "fusonic/opengraph",
···
"time": "2025-03-24T10:02:05+00:00"
},
-
"name": "nette/php-generator",
-
"version": "v4.2.0",
-
"source": {
-
"type": "git",
-
"url": "https://github.com/nette/php-generator.git",
-
"reference": "4707546a1f11badd72f5d82af4f8a6bc64bd56ac"
-
},
-
"dist": {
-
"type": "zip",
-
"url": "https://api.github.com/repos/nette/php-generator/zipball/4707546a1f11badd72f5d82af4f8a6bc64bd56ac",
-
"reference": "4707546a1f11badd72f5d82af4f8a6bc64bd56ac",
-
"shasum": ""
-
},
-
"require": {
-
"nette/utils": "^4.0.6",
-
"php": "8.1 - 8.5"
-
},
-
"require-dev": {
-
"jetbrains/phpstorm-attributes": "^1.2",
-
"nette/tester": "^2.4",
-
"nikic/php-parser": "^5.0",
-
"phpstan/phpstan-nette": "^2.0@stable",
-
"tracy/tracy": "^2.8"
-
},
-
"suggest": {
-
"nikic/php-parser": "to use ClassType::from(withBodies: true) & ClassType::fromCode()"
-
},
-
"type": "library",
-
"extra": {
-
"branch-alias": {
-
"dev-master": "4.2-dev"
-
}
-
},
-
"autoload": {
-
"psr-4": {
-
"Nette\\": "src"
-
},
-
"classmap": [
-
"src/"
-
]
-
},
-
"notification-url": "https://packagist.org/downloads/",
-
"license": [
-
"BSD-3-Clause",
-
"GPL-2.0-only",
-
"GPL-3.0-only"
-
],
-
"authors": [
-
{
-
"name": "David Grudl",
-
"homepage": "https://davidgrudl.com"
-
},
-
{
-
"name": "Nette Community",
-
"homepage": "https://nette.org/contributors"
-
}
-
],
-
"description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.5 features.",
-
"homepage": "https://nette.org",
-
"keywords": [
-
"code",
-
"nette",
-
"php",
-
"scaffolding"
-
],
-
"support": {
-
"issues": "https://github.com/nette/php-generator/issues",
-
"source": "https://github.com/nette/php-generator/tree/v4.2.0"
-
},
-
"time": "2025-08-06T18:24:31+00:00"
-
},
-
{
"name": "nette/schema",
"version": "v1.3.2",
"source": {
···
],
"time": "2025-01-02T08:10:11+00:00"
+
}
+
],
+
"packages-dev": [
+
{
+
"name": "flightphp/tracy-extensions",
+
"version": "v0.2.7",
+
"source": {
+
"type": "git",
+
"url": "https://github.com/flightphp/tracy-extensions.git",
+
"reference": "4150ea7dc9bbb56fa089e7a4662f68011a771256"
+
},
+
"dist": {
+
"type": "zip",
+
"url": "https://api.github.com/repos/flightphp/tracy-extensions/zipball/4150ea7dc9bbb56fa089e7a4662f68011a771256",
+
"reference": "4150ea7dc9bbb56fa089e7a4662f68011a771256",
+
"shasum": ""
+
},
+
"require": {
+
"flightphp/core": "^3.0",
+
"php": ">=8.0",
+
"tracy/tracy": "^2.10"
+
},
+
"require-dev": {
+
"ghostff/session": "^2.1"
+
},
+
"type": "library",
+
"autoload": {
+
"classmap": [
+
"src/"
+
]
+
},
+
"notification-url": "https://packagist.org/downloads/",
+
"license": [
+
"MIT"
+
],
+
"authors": [
+
{
+
"name": "n0nag0n",
+
"email": "n0nag0n@sky-9.com"
+
}
+
],
+
"description": "A few Flight specific extensions for Tracy Debugger to help debug your code quickly.",
+
"support": {
+
"issues": "https://github.com/flightphp/tracy-extensions/issues",
+
"source": "https://github.com/flightphp/tracy-extensions/tree/v0.2.7"
+
},
+
"time": "2025-09-03T13:47:57+00:00"
},
"name": "tracy/tracy",
···
"source": "https://github.com/nette/tracy/tree/v2.10.10"
},
"time": "2025-04-28T14:35:15+00:00"
-
}
-
],
-
"packages-dev": [
-
{
-
"name": "flightphp/tracy-extensions",
-
"version": "v0.2.7",
-
"source": {
-
"type": "git",
-
"url": "https://github.com/flightphp/tracy-extensions.git",
-
"reference": "4150ea7dc9bbb56fa089e7a4662f68011a771256"
-
},
-
"dist": {
-
"type": "zip",
-
"url": "https://api.github.com/repos/flightphp/tracy-extensions/zipball/4150ea7dc9bbb56fa089e7a4662f68011a771256",
-
"reference": "4150ea7dc9bbb56fa089e7a4662f68011a771256",
-
"shasum": ""
-
},
-
"require": {
-
"flightphp/core": "^3.0",
-
"php": ">=8.0",
-
"tracy/tracy": "^2.10"
-
},
-
"require-dev": {
-
"ghostff/session": "^2.1"
-
},
-
"type": "library",
-
"autoload": {
-
"classmap": [
-
"src/"
-
]
-
},
-
"notification-url": "https://packagist.org/downloads/",
-
"license": [
-
"MIT"
-
],
-
"authors": [
-
{
-
"name": "n0nag0n",
-
"email": "n0nag0n@sky-9.com"
-
}
-
],
-
"description": "A few Flight specific extensions for Tracy Debugger to help debug your code quickly.",
-
"support": {
-
"issues": "https://github.com/flightphp/tracy-extensions/issues",
-
"source": "https://github.com/flightphp/tracy-extensions/tree/v0.2.7"
-
},
-
"time": "2025-09-03T13:47:57+00:00"
],
"aliases": [],
data/sbs.db.example

This is a binary file and will not be displayed.

+7 -6
index.php
···
Flight::route('/f/@did:did:plc:[0-9a-z]+/@name:[a-z0-9\-\_]+', function (string $did, string $name): void {
$bskyToucher = new BskyToucher();
$feedUrl = "at://".$did."/app.bsky.feed.generator/".$name;
-
$feedInfo = $bskyToucher->getFeedInfo("at://".$did."/app.bsky.feed.generator/".$name);
+
$feedInfo = $bskyToucher->getFeedInfo($feedUrl);
+
$creatorInfo = $bskyToucher->getUserInfo($feedInfo->creator_did);
$posts = $bskyToucher->getFeed($feedUrl);
$latte = new Latte\Engine;
$latte->render('./templates/feed.latte', array_merge(Flight::get('standardParams'), [
'mainClass' => 'feed',
'posts' => $posts,
-
'feedName' => $feedInfo->displayName,
+
'feedName' => $feedInfo->title,
'feedAvatar' => $feedInfo->avatar,
'feedDescription' => $feedInfo->description,
'feedAtUri' => $feedUrl,
-
'feedAuthorName' => $feedInfo->creatorDisplay,
-
'feedAuthorHandle' => $feedInfo->creatorHandle,
-
'feedAuthorDid' => $feedInfo->creatorDid,
-
'feedAuthorPds' => $feedInfo->creatorPds
+
'feedAuthorName' => $creatorInfo->displayName,
+
'feedAuthorHandle' => $creatorInfo->handle,
+
'feedAuthorDid' => $creatorInfo->did,
+
'feedAuthorPds' => $creatorInfo->pds
]));
});
+87 -80
lib/bskyToucher.php
···
require_once('config.php');
require_once('vendor/autoload.php');
require_once('bskyProvider.php');
+
require_once('db.php');
use Smallnest\Bsky\BskyProvider;
use Smallnest\Bsky\BskyRenderer;
···
}
function getPlcInfoFromRecord(string $did):object|bool {
-
$plcdirBase = "https://plc.directory/";
+
$cache = \requestPlcCache($did);
+
if ($cache) {
+
$doc = json_decode($cache->plcdoc);
+
return (object) [
+
'pds' => $doc->service[0]->serviceEndpoint,
+
'did' => $did,
+
'handle' => str_replace("at://", "", $doc->alsoKnownAs[0])
+
];
+
}
+
+
$plcdirBase = \PLC_DIRECTORY."/";
$ret = $this->makeRequest("GET", $plcdirBase.$did);
if ($ret && $ret->getReasonPhrase() === 'OK') {
-
$resp = json_decode((string) $ret->getBody());
+
$body = $ret->getBody();
+
\updatePlcCache($did, (string) $body);
+
$resp = json_decode((string) $body);
if ($resp && property_exists($resp, 'service') && is_array($resp->service) && count($resp->service) > 0 && property_exists($resp->service[0], 'serviceEndpoint')) {
$handle = "";
···
/* USER INFO */
-
function getUserInfo(string $identifier): object|bool {
-
echo 'hello world';
-
print_r($identifier);
+
function getUserInfo(string $identifier, string $type = 'handle'): object|bool {
+
$cache = \requestUserCache($identifier, $type);
+
if ($cache) return $cache;
$userData = $this->getSlingshotIdentityMiniDoc($identifier);
-
print_r($userData);
$did = $userData->did;
$pds = $userData->pds;
$userInfo = $this->getSlingshotData($did, 'app.bsky.actor.profile', 'self');
if ($userInfo) {
+
$avatar = property_exists($userInfo->value, 'avatar') ? $this->getMediaUrl($pds, $did, $userInfo->value->avatar->ref->{'$link'}) : null;
+
$banner = property_exists($userInfo->value, 'banner') ? $this->getMediaUrl($pds, $did, $userInfo->value->banner->ref->{'$link'}) : null;
+
$pinned = property_exists($userInfo->value, 'pinnedPost') ? $userInfo->value->pinnedPost->uri : null;
+
\updateUserCache($userData->handle, $did, $userInfo->value->displayName, $pds, $avatar, $banner, $userInfo->value->description, $pinned);
return (object) [
'handle' => $userData->handle,
'displayName' => $userInfo->value->displayName,
'did' => $did,
'pds' => $pds,
'description' => $userInfo->value->description,
-
'avatar' => property_exists($userInfo->value, 'avatar') ? $this->getMediaUrl($pds, $did, $userInfo->value->avatar->ref->{'$link'}) : null,
-
'banner' => property_exists($userInfo->value, 'banner') ? $this->getMediaUrl($pds, $did, $userInfo->value->banner->ref->{'$link'}) : null,
-
'pinnedPost' => property_exists($userInfo->value, 'pinnedPost') ? $userInfo->value->pinnedPost->uri : null
+
'avatar' => $avatar,
+
'banner' => $banner,
+
'pinnedPost' => $pinned
];
}
return false;
···
/* POSTS */
function getPost(string $identifier, string $rkey, $slingshot = false):object|bool {
-
if (!$slingshot) {
-
return false;
+
$cache = \requestPostCache($rkey);
+
if ($cache) {
+
$ret = $cache;
+
$authorInfo = $this->getUserInfo($ret->did, 'did');
+
$ret->author = (object) [
+
'displayName' => $authorInfo->displayName,
+
'handle' => $authorInfo->handle,
+
'did' => $ret->did,
+
'avatar' => $authorInfo->avatar
+
];
+
return $ret;
}
+
$ret = $this->getSlingshotData($identifier, "app.bsky.feed.post", $rkey);
-
$userInfo = $this->getSlingshotData($identifier, "app.bsky.actor.profile", "self");
-
$uriComponents = $this->splitAtUri($userInfo->uri);
-
$did = $uriComponents->did;
-
$plcData = $this->getPlcInfoFromRecord($did);
+
if (!$ret) return false;
+
$userInfo = $this->getUserInfo($identifier);
$author = (object) [
-
'displayName' => $userInfo->value->displayName,
-
'handle' => $plcData->handle,
-
'did' => $did,
-
'avatar' => $this->getMediaUrl($plcData->pds, $did, $userInfo->value->avatar->ref->{'$link'})
+
'displayName' => $userInfo->displayName,
+
'handle' => $userInfo->handle,
+
'did' => $userInfo->did,
+
'avatar' => $this->getMediaUrl($plcData->pds, $did, $userInfo->avatar)
];
$ret->author = $author;
-
if ($ret) {
-
return $this->sanitizePost($ret, true);
-
}
-
return false;
+
print_r($ret);
+
$post = $this->sanitizePost($ret, true);
+
\updatePostCache($post->rkey, $post->did, $post->text, $post->embed_type, json_encode($post->embeds));
+
return $post;
}
function getLikes(string $post):int {
···
}
function getUserPosts(string $did, $auth = false, $cursor = null, $newer = false):array|bool {
-
$userData = $this->getSlingshotIdentityMiniDoc($did);
+
$userData = $this->getUserInfo($did, 'did');
$postData = $this->getPdsData($userData->pds, 'com.atproto.repo.listRecords', [
'repo' => $did,
'collection' => 'app.bsky.feed.post',
+
'limit' => 20,
'cursor' => $cursor
]);
···
$deferred = new \React\Promise\Deferred();
$deferred->promise()
->then(function($x) {
-
React\Async\parallel(array_map(function($p) {
-
return function () {
-
global $p;
-
return new Promise(function ($resolve) {
-
global $p;
+
\React\Async\parallel(array_map(function($p) {
+
return function () use ($p) {
+
return new Promise(function ($resolve) use ($p) {
$bskyToucher = new BskyToucher;
-
$resolve($bskyToucher->sanitizePost($p));
+
$uriComponents = $this->splitAtUri($p->uri);
+
$cache = \requestPostCache($uriComponents->rkey);
+
if (!$cache) {
+
$resolve($bskyToucher->sanitizePost($p, true));
+
} else {
+
$resolve($cache);
+
}
});
};
}, $x))
···
return $results;
})->catch(function (Exception $e) {
echo 'Error: ' . $e->getMessage() . PHP_EOL;
+
return false;
});
}, function (Exception $e) {
echo 'Error: ' . $e->getMessage() . PHP_EOL;
+
return false;
});
-
$postData = $deferred->resolve($postData);
+
$postData = $deferred->resolve($postData->records);
if (!$postData) return false;
···
}
function getFeedInfo(string $atUri): object|bool {
+
$cache = \requestFeedCache($atUri);
+
if ($cache) return $cache;
+
$uriComponents = $this->splitAtUri($atUri);
if (!$uriComponents) return false;
$feedData = $this->getSlingshotData($uriComponents->did, $uriComponents->collection, $uriComponents->rkey);
-
$plcInfo = $this->getPlcInfoFromRecord($uriComponents->did);
-
$authorInfo = $this->getSlingshotData($uriComponents->did, 'app.bsky.actor.profile', 'self');
+
$authorInfo = $this->getUserInfo($uriComponents->did, 'did');
+
\updateFeedCache($atUri, $feedData->value->displayName, $feedData->value->description, $feedData->value->avatar->ref->{'$link'}, $uriComponents->did);
return (object) [
'mainClass' => 'feed',
-
'displayName' => $feedData->value->displayName,
+
'title' => $feedData->value->displayName,
'url' => '/f/'.$uriComponents->did.'/'.$uriComponents->rkey,
'description' => $feedData->value->description,
-
'avatar' => $this->getMediaUrl($plcInfo->pds, $uriComponents->did, $feedData->value->avatar->ref->{'$link'}),
-
'creatorDisplay' => $authorInfo->value->displayName,
+
'avatar' => $this->getMediaUrl($authorInfo->pds, $uriComponents->did, $feedData->value->avatar->ref->{'$link'}),
+
'creatorDisplay' => $authorInfo->displayName,
'creatorDid' => $uriComponents->did,
-
'creatorPds' => $plcInfo->pds,
-
'creatorHandle' => $plcInfo->handle
+
'creatorPds' => $authorInfo->pds,
+
'creatorHandle' => $authorInfo->handle
];
return $feedData;
}
···
if (!$uriComponents) return false;
$did = $uriComponents[1];
$rkey = $uriComponents[2];
-
$authorData = $this->getSlingshotIdentityMiniDoc($did);
-
$authorInfo = $this->getSlingshotData($did, 'app.bsky.actor.profile', 'self');
+
$authorInfo = $this->getUserInfo($did, 'did');
$facets = property_exists($post->value, 'facets') ? $this->sanitizeFacets($post->value->facets) : [];
$ret = (object) [
-
'displayName' => property_exists($authorInfo->value, 'displayName') && $authorInfo->value->displayName !== "" ? $authorInfo->value->displayName : $authorInfo->handle,
-
'handle' => $authorData->handle,
-
'profileLink' => '/u/'.$authorData->handle,
-
'avatar' => property_exists($authorInfo->value, 'avatar') ? $this->getMediaUrl($authorData->pds, $did, $authorInfo->value->avatar->ref->{'$link'}) : null,
+
'displayName' => $authorInfo->displayName,
+
'handle' => $authorInfo->handle,
+
'profileLink' => '/u/'.$authorInfo->handle,
+
'avatar' => $authorInfo->avatar,
'did' => $did,
'uri' => $post->uri,
-
'pds' => $authorData->pds,
+
'pds' => $authorInfo->pds,
'postId' => $rkey,
-
'postLink' => '/u/'.$authorData->handle.'/'.$rkey,
+
'postLink' => '/u/'.$authorInfo->handle.'/'.$rkey,
'content' => $this->applyFacets($post->value->text, $facets),
'replyCount' => $this->getReplies($post->uri),
'repostCount' => $this->getReposts($post->uri),
···
'embeds' => property_exists($post->value, 'embed') ? $this->sanitizeEmbeds($post->value->embed, $authorData) : [],
'cursor' => null
];
+
print_r($ret);
+
\updatePostCache($rkey, $did, $ret->$content, $ret->embedType, json_encode($ret->$embeds));
return $ret;
}
function sanitizePublicApiPost(object $post):object|bool {
preg_match('/at:\/\/(did:plc:[a-z0-9]+)\/[a-zA-Z\.]+\/([a-z0-9]+)/', $post->uri, $rkeyMatch);
if (!$rkeyMatch) return false;
-
$authorData = $this->getSlingshotIdentityMiniDoc($post->author->did);
+
$authorData = $this->getUserInfo($post->author->did, 'did');
$facets = property_exists($post->record, 'facets') ? $this->sanitizeFacets($post->record->facets) : [];
return (object) [
-
'displayName' => property_exists($post->author, 'displayName') && $post->author->displayName !== "" ? $post->author->displayName : $post->author->handle,
+
'displayName' => $authorData->displayName,
'handle' => $authorData->handle,
'did' => $authorData->did,
'profileLink' => '/u/'.$authorData->handle,
-
'avatar' => $post->author->avatar,
-
'banner' => property_exists($post->author, 'banner') ? $post->author->banner : null,
+
'avatar' => $authorData->avatar,
+
'banner' => $authorData->banner,
'uri' => $post->uri,
'pds' => $authorData->pds,
'postId' => $rkeyMatch[2],
···
'quoteCount' => $post->quoteCount,
'createdAt' => $post->record->createdAt,
'embedType' => property_exists($post->record, 'embed') ? $post->record->embed->{'$type'} : null,
-
'embeds' => property_exists($post->record, 'embed') ? $this->sanitizeEmbeds($post->record->embed, $authorData) : [],
-
'cursor' => ''
+
'embeds' => property_exists($post->record, 'embed') ? $this->sanitizeEmbeds($post->record->embed, $authorData) : []
];
}
···
return false;
}
-
function sanitizeUser(string $handle):object {
-
$ret = $this->getSlingshotIdentityMiniDoc($handle);
-
$pds = $ret->pds;
-
$did = $ret->did;
-
$userInfo = $this->getSlingshotData($did, 'app.bsky.actor.profile', 'self');
-
$userPosts = $this->getUserPosts($handle);
-
return (object) [
-
'displayName' => $userInfo->value->displayName ? $userInfo->value->displayName : $handle,
-
'handle' => $handle,
-
'did' => $did,
-
'pds' => $pds,
-
'avatar' => $this->getMediaUrl($pds, $did, $userInfo->value->avatar->ref->{'$link'}),
-
'banner' => $this->getMediaUrl($pds, $did, $userInfo->value->banner->ref->{'$link'}),
-
'description' => $userInfo->value->description,
-
'posts' => $userPosts
-
];
-
}
-
function sanitizeUserList(array $users):array {
$normalized = array_map(function ($rec) {
$hydratedRec = $rec;
-
$actorSlingshot = $this->getSlingshotData($rec->did, 'app.bsky.actor.profile', 'self');
-
if (!$actorSlingshot) return false;
-
$actorData = $this->getPlcInfoFromRecord($rec->did);
-
$hydratedRec->actor = (object) [
-
'displayName' => $actorSlingshot->value->displayName !== "" ? htmlspecialchars($actorSlingshot->value->displayName) : $actorData->handle,
-
'handle' => $actorData->handle,
-
'did' => $rec->did,
-
'avatar' => $this->getMediaUrl($actorData->pds, $rec->did, $actorSlingshot->value->avatar->ref->{'$link'})
-
];
-
return $hydratedRec;
+
return $this->getUserInfo($rec->did, 'did');
}, $users);
$ret = array_values(array_filter($normalized));
return $ret;
+132
lib/db.php
···
+
<?php
+
require_once('config.php');
+
require_once('vendor/autoload.php');
+
+
$db = new SQLite3('../data/sbs.db');
+
+
/* TABLE OF CONTENTS ==========
+
I. Cleanup
+
II. Cache Requests
+
III. Cache Updates
+
IV. User Ban/Suspension Lookup
+
V. User Ban/Susppension Management
+
*/
+
+
/* I. CLEANUP */
+
+
function deleteExpired(string $table): void {
+
global $db;
+
$db->exec('delete from '.$table.' where expires <= '.strtotime('now').';');
+
}
+
+
/* II. CACHE REQUESTS */
+
+
function requestUserCache(string $value, string $field = "handle"): object|bool {
+
global $db;
+
deleteExpired('user_cache');
+
$result = $db->query("select * from user_cache where ".$field."='".$value."' limit 1;");
+
$arr = $result->fetchArray();
+
if (!is_array($arr) || count($arr) === 0) return false;
+
$arr['displayName'] = $arr['display_name'];
+
$arr['pinnedPost'] = $arr['pinned_post'];
+
unset($arr['display_name']);
+
unset($arr['pinned_post']);
+
return (object) $arr;
+
}
+
+
function requestPlcCache(string $did): object|bool {
+
global $db;
+
deleteExpired('plc_cache');
+
$result = $db->query("select * from plc_cache where did='".$did."' limit 1;");
+
$arr = $result->fetchArray();
+
if (is_array($arr) && count($arr) > 0) return (object) $arr;
+
return false;
+
}
+
+
function requestFeedCache(string $atUri): object|bool {
+
global $db;
+
deleteExpired('feed_cache');
+
$result = $db->query("select * from feed_cache where at_uri='".$atUri."' limit 1;");
+
$arr = $result->fetchArray();
+
if (is_array($arr) && count($arr) > 0) return (object) $arr;
+
return false;
+
}
+
+
function requestPostCache(string $rkey): object|bool {
+
global $db;
+
deleteExpired('post_cache');
+
$result = $db->query("select * from post_cache where rkey='".$rkey."' limit 1;");
+
$arr = $result->fetchArray();
+
if (is_array($arr) && count($arr) > 0) {
+
$arr['embedType'] = $arr['embed_type'];
+
$arr['embeds'] = $arr['embed_data'];
+
unset($arr['embed_type']);
+
unset($arr['embed_data']);
+
return (object) $arr;
+
}
+
return false;
+
}
+
+
/* III. CACHE UPDATES */
+
+
function updateUserCache(string $handle, string $did, ?string $displayName, string $pds, ?string $avatar, ?string $banner, ?string $description, ?string $pinned): void {
+
global $db;
+
$newExpiration = strtotime('now') + 60*60;
+
if (requestUserCache($did, 'did')) {
+
$db->exec("update user_cache set handle='".$handle."', display_name='".SQLite3::escapeString($displayName)."', pds='".$pds."', avatar='".$avatar."', banner='".$banner."', description='".SQLite3::escapeString($description)."', pinned_post='".$pinned."', expires='".$newExpiration."' where did='".$did."';");
+
} else {
+
$db->exec("insert into user_cache (handle, did, display_name, pds, avatar, banner, description, pinned_post, expires) values ('".$handle."', '".$did."', '".SQLite3::escapeString($displayName)."', '".$pds."', '".$avatar."', '".$banner."', '".SQLite3::escapeString($description)."', '".$pinned."', '".$newExpiration."');");
+
}
+
}
+
+
function updatePlcCache(string $did, string $plcdoc): void {
+
global $db;
+
$newExpiration = strtotime('now') + 60*60*48;
+
if (requestPlcCache($did)) {
+
$db->exec("update plc_cache set plcdoc='".$plcdoc."', expires='".$newExpiration."' where did='".$did."';");
+
} else {
+
$db->exec("insert into plc_cache (did, plcdoc, expires) values ('".$did."', '".$plcdoc."', '".$newExpiration."');");
+
}
+
}
+
+
function updateFeedCache(string $atUri, string $title, ?string $description, ?string $avatar, string $creator_did) {
+
global $db;
+
$newExpiration = strtotime('now') + 60*60*4;
+
if (requestFeedCache($atUri)) {
+
$db->exec("update feed_cache set title='".SQLite3::escapeString($title)."', description='".SQLite3::escapeString($description)."', avatar='".$avatar."', creator_did='".$creator_did."', expires='".$newExpiration."' where at_uri='".$atUri."';");
+
} else {
+
$db->exec("insert into feed_cache (at_uri, title, description, avatar, creator_did, expires) values ('".$atUri."', '".SQLite3::escapeString($title)."', '".SQLite3::escapeString($description)."', '".$avatar."', '".$creator_did."', '".$newExpiration."');");
+
}
+
}
+
+
function updatePostCache(string $rkey, string $did, string $text, ?string $embedType, ?string $embedData): void {
+
global $db;
+
$newExpiration = strtotime('now') + 60*60*48;
+
if (requestPlcCache($did)) {
+
$db->exec("update post_cache set text='".SQLite3::escapeString($text)."', embed_type='".$embedtype."' where embed_data='".SQLite3::escapeString($embedData)."', expires='".$newExpiration."' where rkey='".$rkey."';");
+
} else {
+
$db->exec("insert into post_cache (rkey, did, text, embed_type, embed_data, expires) values ('".$rkey."', '".$did."', '".SQLite3::escapeString($text)."', '".$embedType."', '".SQLite3::escapeString($embedData)."', '".$newExpiration."');");
+
}
+
}
+
+
/* IV. USER BAN/SUSPENSION LOOKUP */
+
+
function isUserCensured($did, $pds) {
+
global $db;
+
deleteExpired("client_suspensions");
+
$ban = $db->query("select count(*) from bans where did='".$did."';");
+
$pdsban = $db->query("select count(*) from pds_bans where domain='".$domain."';");
+
$suspension = $db->query("select count(*) from client_suspensions where did='".$did."' and expires > ".strtotime('now').";");
+
if ($ban > 0 || $pdsban > 0 || $suspension > 0) {
+
return true;
+
}
+
return false;
+
}
+
+
function getUserCensureInfo($did, $pds) {
+
+
}
+
+
/* V. USER BAN/SUSPENSION MANAGEMENT */
+
+
?>
+2
templates/feed.latte
···
{layout 'layout.latte'}
+
{block title} | {$feedName}{/block}
+
{block content}
{include '_partials/feedHeader.latte', displayName: $feedName, description: $description, avatar: $avatar, creatorDisplay: $creatorDisplay, creatorHandle: $creatorHandle, creatorPds: $creatorPds, creatorDid: $creatorDid, feedAtUri: $feedAtUri}
{include '_partials/feedPosts.latte', posts: $posts}
-257
vendor/adhocore/cli/CHANGELOG.md
···
-
## [v1.2.0](https://github.com/adhocore/php-cli/releases/tag/v1.2.0) (2022-10-08)
-
-
### Features
-
- **App**: Set common group to commands set via callable (Jitendra Adhikari) [_6c6e53c_](https://github.com/adhocore/php-cli/commit/6c6e53c)
-
- **Helper**: Support grouped sorting for show help (Jitendra Adhikari) [_314a887_](https://github.com/adhocore/php-cli/commit/314a887)
-
- **Input**: Add Groupable interface, make Command groupable (Jitendra Adhikari) [_29b09ce_](https://github.com/adhocore/php-cli/commit/29b09ce)
-
-
### Bug Fixes
-
- Adapt for strict type php8 (Jitendra Adhikari) [_8198969_](https://github.com/adhocore/php-cli/commit/8198969)
-
-
### Internal Refactors
-
- *****: Use imports instead of FQN (Jitendra Adhikari) [_bd0a70c_](https://github.com/adhocore/php-cli/commit/bd0a70c)
-
-
### Miscellaneous
-
- **Travis**: Retire it :( (Jitendra Adhikari) [_70e510b_](https://github.com/adhocore/php-cli/commit/70e510b)
-
-
### Documentations
-
- Add Grouping commands section (Jitendra Adhikari) [_3e05837_](https://github.com/adhocore/php-cli/commit/3e05837)
-
-
### Builds
-
- **Workflow**: Add github action build (Jitendra Adhikari) [_9b4da7d_](https://github.com/adhocore/php-cli/commit/9b4da7d)
-
-
-
## [v1.0.1](https://github.com/adhocore/php-cli/releases/tag/v1.0.1) (2022-07-05)
-
-
### Bug Fixes
-
- Correct io() fallback mechanism (Daniel Jakob) [_4072eaf_](https://github.com/adhocore/php-cli/commit/4072eaf)
-
-
-
## [v1.0.0](https://github.com/adhocore/php-cli/releases/tag/v1.0.0) (2022-06-30)
-
-
### Bug Fixes
-
- **Shell**: Exitcode is null first (Jitendra Adhikari)
-
-
### Internal Refactors
-
- Add typehints, remove redundant docblocks (Jitendra Adhikari)
-
- Use php8 syntax (Jitendra Adhikari)
-
-
### Miscellaneous
-
- Typehint (Jitendra)
-
- Run on >= php8 (Jitendra Adhikari)
-
- Use php8 deps (Jitendra Adhikari)
-
-
-
## [0.9.1](https://github.com/adhocore/php-cli/releases/tag/0.9.1) (2022-02-18)
-
-
### Bug Fixes
-
- Php8.1 substr, d197dc6 (Jitendra A)
-
-
-
## [0.8.4](https://github.com/adhocore/php-cli/releases/tag/0.8.4) (2020-10-09)
-
-
### Builds
-
- **Travis**: Add php 7.3 and 7.4 (Jitendra Adhikari) [_a5c4a16_](https://github.com/adhocore/php-cli/commit/a5c4a16)
-
-
-
## [0.8.3](https://github.com/adhocore/php-cli/releases/tag/0.8.3) (2020-01-05)
-
-
### Internal Refactors
-
- **App**: Extract cmd not found to outputhelper (Jitendra Adhikari) [_c317634_](https://github.com/adhocore/php-cli/commit/c317634)
-
-
-
## [0.8.2](https://github.com/adhocore/php-cli/releases/tag/0.8.2) (2020-01-03)
-
-
### Bug Fixes
-
- **Normalizer**: Complex option containing value delimited by = (Jitendra Adhikari) [_5d5394a_](https://github.com/adhocore/php-cli/commit/5d5394a)
-
-
-
## [0.8.1](https://github.com/adhocore/php-cli/releases/tag/0.8.1) (2020-01-03)
-
-
### Bug Fixes
-
- **Cmd.action**: Can be array too (besides closure/null) (Jitendra Adhikari) [_238c8b1_](https://github.com/adhocore/php-cli/commit/238c8b1)
-
-
-
## [0.8.0](https://github.com/adhocore/php-cli/releases/tag/0.8.0) (2020-01-03)
-
-
### Features
-
- **Cmd.action**: Bind to $this (Jitendra Adhikari) [_c479995_](https://github.com/adhocore/php-cli/commit/c479995)
-
-
### Documentations
-
- Add credits, update license year (Jitendra Adhikari) [_2bf08c5_](https://github.com/adhocore/php-cli/commit/2bf08c5)
-
-
-
## [0.7.3](https://github.com/adhocore/php-cli/releases/tag/0.7.3) (2020-01-03)
-
-
### Internal Refactors
-
- **App**: Add onExit prop, execute or action can return exit code (Jitendra Adhikari) [_1e754a8_](https://github.com/adhocore/php-cli/commit/1e754a8)
-
-
### Documentations
-
- About cmd exit code (Jitendra Adhikari) [_32d45c2_](https://github.com/adhocore/php-cli/commit/32d45c2)
-
- About cmd usage ($0 and ##) (Jitendra Adhikari) [_2319370_](https://github.com/adhocore/php-cli/commit/2319370)
-
-
-
## [0.7.2](https://github.com/adhocore/php-cli/releases/tag/0.7.2) (2020-01-02)
-
-
### Bug Fixes
-
- **Cmd.help**: Usage label was printed even if no text (Jitendra Adhikari) [_4639624_](https://github.com/adhocore/php-cli/commit/4639624)
-
-
-
## [0.7.1](https://github.com/adhocore/php-cli/releases/tag/0.7.1) (2020-01-02)
-
-
### Bug Fixes
-
- **Phpunit**: Rm xml.syntaxCheck (Jitendra Adhikari) [_6ae66b0_](https://github.com/adhocore/php-cli/commit/6ae66b0)
-
-
### Internal Refactors
-
- **Interactor**: Reduce complexity in prompt (Jitendra Adhikari) [_dd008af_](https://github.com/adhocore/php-cli/commit/dd008af)
-
-
### Miscellaneous
-
- **Composer**: Tweak script.test (Jitendra Adhikari) [_9b8ee5d_](https://github.com/adhocore/php-cli/commit/9b8ee5d)
-
- **Travis**: Script (Jitendra Adhikari) [_c41e256_](https://github.com/adhocore/php-cli/commit/c41e256)
-
-
-
## [0.7.0](https://github.com/adhocore/php-cli/releases/tag/0.7.0) (2019-12-30)
-
-
### Bug Fixes
-
- **Output.helper**: Pad ## (Jitendra Adhikari) [_73a4a4e_](https://github.com/adhocore/php-cli/commit/73a4a4e)
-
- **Normalizer**: Invert bool iff type is bool not value (Jitendra Adhikari) [_6ff4acd_](https://github.com/adhocore/php-cli/commit/6ff4acd)
-
-
### Internal Refactors
-
- **Option**: Improve bool() check (Jitendra Adhikari) [_e7e95e3_](https://github.com/adhocore/php-cli/commit/e7e95e3)
-
-
-
## [0.6.2](https://github.com/adhocore/php-cli/releases/tag/0.6.2) (2019-12-30)
-
-
### Bug Fixes
-
- **Color**: Comment line shows white trailing bar (daemonu) [_b578d9a_](https://github.com/adhocore/php-cli/commit/b578d9a)
-
-
-
## [0.6.1](https://github.com/adhocore/php-cli/releases/tag/0.6.1) (2019-12-29)
-
-
### Miscellaneous
-
- Extend exception from throwable (Jitendra Adhikari) [_ab6b351_](https://github.com/adhocore/php-cli/commit/ab6b351)
-
-
-
## [0.6.0](https://github.com/adhocore/php-cli/releases/tag/0.6.0) (2019-12-26)
-
-
### Features
-
- **Table**: Add table renderer class (Jitendra Adhikari) [_808e80e_](https://github.com/adhocore/php-cli/commit/808e80e)
-
- **Reader**: Add readAll() (Jitendra Adhikari) [_9264082_](https://github.com/adhocore/php-cli/commit/9264082)
-
- **Output**: Add show usage (Jitendra Adhikari) [_1356515_](https://github.com/adhocore/php-cli/commit/1356515)
-
- **Reader**: Add read piped (Jitendra Adhikari) [_790f2a1_](https://github.com/adhocore/php-cli/commit/790f2a1)
-
-
### Internal Refactors
-
- **Reader**: Visibility (Jitendra Adhikari) [_bcea11b_](https://github.com/adhocore/php-cli/commit/bcea11b)
-
- **Writer**: Use Table::render instead (Jitendra Adhikari) [_f0f33ee_](https://github.com/adhocore/php-cli/commit/f0f33ee)
-
- **Command**: Use helper showUsage() instead (Jitendra Adhikari) [_ef5ea2b_](https://github.com/adhocore/php-cli/commit/ef5ea2b)
-
-
### Miscellaneous
-
- **Composer**: Add test scripts (Jitendra Adhikari) [_4d292ca_](https://github.com/adhocore/php-cli/commit/4d292ca)
-
- **Color**: Add dark and light gray colors (Jitendra Adhikari) [_2d4051d_](https://github.com/adhocore/php-cli/commit/2d4051d)
-
-
### Documentations
-
- Add readAll() usage (Jitendra Adhikari) [_62cbfd0_](https://github.com/adhocore/php-cli/commit/62cbfd0)
-
- Update intro and credits (Jitendra Adhikari) [_7cbaae6_](https://github.com/adhocore/php-cli/commit/7cbaae6)
-
- Add readHidden, readPiped usage (Jitendra Adhikari) [_57dae5e_](https://github.com/adhocore/php-cli/commit/57dae5e)
-
-
-
## [0.5.0](https://github.com/adhocore/php-cli/releases/tag/0.5.0) (2019-09-16)
-
-
### Features
-
- **Reader**: Add read hidden for win os (Jitendra Adhikari) [_742c622_](https://github.com/adhocore/php-cli/commit/742c622)
-
-
### Internal Refactors
-
- **Interactor**: Prompt hidden now supported in win os (Jitendra Adhikari) [_491d162_](https://github.com/adhocore/php-cli/commit/491d162)
-
-
### Documentations
-
- Add a note about hidden prompt on win os (Jitendra Adhikari) [_43fe762_](https://github.com/adhocore/php-cli/commit/43fe762)
-
-
-
## [0.4.0](https://github.com/adhocore/php-cli/releases/tag/0.4.0) (2019-09-07)
-
-
### Features
-
- **Interactor**: Add promptHidden (unix only) (Jitendra Adhikari) [_1eb06c6_](https://github.com/adhocore/php-cli/commit/1eb06c6)
-
- **Reader**: Add readHidden (Jitendra Adhikari) [_3628331_](https://github.com/adhocore/php-cli/commit/3628331)
-
-
### Documentations
-
- About hidden prompt (Jitendra Adhikari) [_af086f9_](https://github.com/adhocore/php-cli/commit/af086f9)
-
-
-
## [0.3.3] 2019-03-09 06:03:34 UTC
-
-
- [573d3c1](https://github.com/adhocore/php-cli/commit/573d3c1) refactor: remove sc folder and update readme with imgur link (Sushil Gupta)
-
- [121ab6c](https://github.com/adhocore/php-cli/commit/121ab6c) refactor(plugin): use gawk, cleanup (Jitendra Adhikari)
-
- [aeaf5f4](https://github.com/adhocore/php-cli/commit/aeaf5f4) refactor(plugin): phpcli => ahccli (Jitendra Adhikari)
-
- [e625fd0](https://github.com/adhocore/php-cli/commit/e625fd0) chore: phpcli => ahccli (Jitendra Adhikari)
-
- [9e31caf](https://github.com/adhocore/php-cli/commit/9e31caf) docs: improve auto completion docs, rename phpcli to ahccli (Jitendra Adhikari)
-
-
## [0.3.2] 2018-09-06 15:09:22 UTC
-
-
- [6e8755f](https://github.com/adhocore/php-cli/commit/6e8755f) docs: autocompletion (Jitendra Adhikari)
-
- [1152671](https://github.com/adhocore/php-cli/commit/1152671) chore(zsh.plugin): auto complete provider for zsh with oh-my-zsh (Jitendra Adhikari)
-
-
## [0.3.1] 2018-09-06 00:09:23 UTC
-
-
- [f390b6b](https://github.com/adhocore/php-cli/commit/f390b6b) refactor: remove redundant codeCoverageIgnore (Sushil Gupta)
-
- [cd8d109](https://github.com/adhocore/php-cli/commit/cd8d109) refactor: minor refactor on messages + add isWindows() method using DIRECTORY_SEPARATOR check to set pipes (Sushil Gupta)
-
-
## [0.3.0] 2018-09-04 15:09:50 UTC
-
-
- [a1c2c30](https://github.com/adhocore/php-cli/commit/a1c2c30) docs: add shell section and contributors (Jitendra Adhikari)
-
- [5146260](https://github.com/adhocore/php-cli/commit/5146260) test: shell tests (Jitendra Adhikari)
-
- [d1e8e73](https://github.com/adhocore/php-cli/commit/d1e8e73) refactor(shell): ignore cov, cleanup etc (Jitendra Adhikari)
-
- [8d5ebe9](https://github.com/adhocore/php-cli/commit/8d5ebe9) feat(shell): a shell wrapper (Jitendra Adhikari)
-
- [37c0e4c](https://github.com/adhocore/php-cli/commit/37c0e4c) Async true gives the process ID (Sushil Gupta)
-
- [1052ca0](https://github.com/adhocore/php-cli/commit/1052ca0) More style fixes (Sushil Gupta)
-
- [989213f](https://github.com/adhocore/php-cli/commit/989213f) Style fixes (Sushil Gupta)
-
- [29e8d13](https://github.com/adhocore/php-cli/commit/29e8d13) If timeout is set, and is set to wait (not async by default), then either wait until it runs or kill it after timeout occurs - if async (not wait) - then don't care about the process at all (Sushil Gupta)
-
- [7cf9536](https://github.com/adhocore/php-cli/commit/7cf9536) If not async, then check for timeout if it is still running and attempt to stop it (Sushil Gupta)
-
- [88bc092](https://github.com/adhocore/php-cli/commit/88bc092) Stop - not kill (Sushil Gupta)
-
- [40ba003](https://github.com/adhocore/php-cli/commit/40ba003) Minor formatting fixed (Sushil Gupta)
-
- [f81237e](https://github.com/adhocore/php-cli/commit/f81237e) Added set options method (Sushil Gupta)
-
- [2d44553](https://github.com/adhocore/php-cli/commit/2d44553) On destruct, if running, waiting until timeout and then attempting to stop, instead of directly attempting to stop (Sushil Gupta)
-
- [acabcca](https://github.com/adhocore/php-cli/commit/acabcca) Root namespace appended for microtime (Sushil Gupta)
-
- [e86580a](https://github.com/adhocore/php-cli/commit/e86580a) Removed redundant unblocking of getOutput (Sushil Gupta)
-
- [76fce1b](https://github.com/adhocore/php-cli/commit/76fce1b) Minor DocBlock update (Sushil Gupta)
-
- [926c4a6](https://github.com/adhocore/php-cli/commit/926c4a6) WIP - Implemented timeout checking and wait system - not working yet (Sushil Gupta)
-
- [641d229](https://github.com/adhocore/php-cli/commit/641d229) Minor refactor - removing updateProcessStatus when asking for getState - not related (Sushil Gupta)
-
- [205daed](https://github.com/adhocore/php-cli/commit/205daed) Refactored to add another state variable to store actual state of the shell execution vs the process status (Sushil Gupta)
-
- [62acd2d](https://github.com/adhocore/php-cli/commit/62acd2d) File default info added (Sushil Gupta)
-
- [acdbd64](https://github.com/adhocore/php-cli/commit/acdbd64) Refactor - assigning default null + only assigning exit value if not already set and process has stopped (Sushil Gupta)
-
- [d742ecb](https://github.com/adhocore/php-cli/commit/d742ecb) Updating status before sending back exitcodes (Sushil Gupta)
-
- [96e3a9e](https://github.com/adhocore/php-cli/commit/96e3a9e) Made private methods protected (Sushil Gupta)
-
- [3939825](https://github.com/adhocore/php-cli/commit/3939825) Setting exit code on proc_close from the proc_get_status itself (Sushil Gupta)
-
- [56ba25d](https://github.com/adhocore/php-cli/commit/56ba25d) Implemented suggestions from code-review (Sushil Gupta)
-
- [dbb3c21](https://github.com/adhocore/php-cli/commit/dbb3c21) Refactored small things (Sushil Gupta)
-
- [13380da](https://github.com/adhocore/php-cli/commit/13380da) Removed timeout - not used anywhere for now (Sushil Gupta)
-
- [2d0f815](https://github.com/adhocore/php-cli/commit/2d0f815) One more style fix (Sushil Gupta)
-
- [e93b398](https://github.com/adhocore/php-cli/commit/e93b398) More style fixes :/ (Sushil Gupta)
-
- [1be59a6](https://github.com/adhocore/php-cli/commit/1be59a6) More style fixes (Sushil Gupta)
-
- [e43a34f](https://github.com/adhocore/php-cli/commit/e43a34f) More style fixes (Sushil Gupta)
-
- [0874497](https://github.com/adhocore/php-cli/commit/0874497) Style fixes - unindenting inside <?php tag (Sushil Gupta)
-
- [5923304](https://github.com/adhocore/php-cli/commit/5923304) Removed vdd (Sushil Gupta)
-
- [304f148](https://github.com/adhocore/php-cli/commit/304f148) Removed wait method - wasn't working - to be added (Sushil Gupta)
-
- [735294c](https://github.com/adhocore/php-cli/commit/735294c) Removed env + cwd from the options, passing null, for the sprit of minimalism ;) (Sushil Gupta)
-
- [bfe1965](https://github.com/adhocore/php-cli/commit/bfe1965) Added basic test case for getOutput (Sushil Gupta)
-
- [4972de3](https://github.com/adhocore/php-cli/commit/4972de3) Moved to helper (Sushil Gupta)
-
- [425af5e](https://github.com/adhocore/php-cli/commit/425af5e) Added pipes for different platform, checking directory separator + added public method to return PID (Sushil Gupta)
-
- [19ce603](https://github.com/adhocore/php-cli/commit/19ce603) Minor refactoring (Sushil Gupta)
-
- [22a759a](https://github.com/adhocore/php-cli/commit/22a759a) Moved public functions to the bottom (Sushil Gupta)
-
- [87ed2e4](https://github.com/adhocore/php-cli/commit/87ed2e4) Made some methods private + added exitCode method (Sushil Gupta)
-
- [c4c4f4e](https://github.com/adhocore/php-cli/commit/c4c4f4e) Added wait and other methods (Sushil Gupta)
-
- [bd54feb](https://github.com/adhocore/php-cli/commit/bd54feb) Using constants for descriptors key (Sushil Gupta)
-
- [4d8578e](https://github.com/adhocore/php-cli/commit/4d8578e) Minor refactoring (Sushil Gupta)
-
- [1e42021](https://github.com/adhocore/php-cli/commit/1e42021) Shell wrapper - basic proc_open implemented (Sushil Gupta)
-
-
## [0.2.1] 2018-08-28 14:08:59 UTC
-
-
- [25c3f1a](https://github.com/adhocore/php-cli/commit/25c3f1a) docs: improve readability and organize (Jitendra Adhikari)
-
-
## [0.2.0] 2018-08-21 14:08:52 UTC
-
-
- [a75c76e](https://github.com/adhocore/php-cli/commit/a75c76e) feat(cmd.option): support multiline desc and indent them properly on help (Jitendra Adhikari)
-
- [7b04d18](https://github.com/adhocore/php-cli/commit/7b04d18) refactor: readme > README (Jitendra Adhikari)
-
- [6e79204](https://github.com/adhocore/php-cli/commit/6e79204) docs: exceptions preview (Jitendra Adhikari)
-
- [c5ffb12](https://github.com/adhocore/php-cli/commit/c5ffb12) test: 100% cov ftw (Jitendra Adhikari)
-
- [92f41ba](https://github.com/adhocore/php-cli/commit/92f41ba) feat(output.helper): add print trace (Jitendra Adhikari)
-
- [7b5080e](https://github.com/adhocore/php-cli/commit/7b5080e) refactor(app): output helper instantiation and print trace (Jitendra Adhikari)
-21
vendor/adhocore/cli/LICENSE
···
-
MIT License
-
-
Copyright (c) 2017-2020 Jitendra Adhikari
-
-
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.
-928
vendor/adhocore/cli/README.md
···
-
## adhocore/cli
-
-
Framework agnostic Command Line Interface utilities and helpers for PHP. Build Console App with ease, fun and love.
-
-
[![Latest Version](https://img.shields.io/github/release/adhocore/php-cli.svg?style=flat-square)](https://github.com/adhocore/php-cli/releases)
-
[![Build](https://github.com/adhocore/php-cli/actions/workflows/build.yml/badge.svg)](https://github.com/adhocore/php-cli/actions/workflows/build.yml)
-
[![Scrutinizer CI](https://img.shields.io/scrutinizer/g/adhocore/php-cli.svg?style=flat-square)](https://scrutinizer-ci.com/g/adhocore/php-cli/?branch=main)
-
[![Codecov branch](https://img.shields.io/codecov/c/github/adhocore/php-cli/main.svg?style=flat-square)](https://codecov.io/gh/adhocore/php-cli)
-
[![StyleCI](https://styleci.io/repos/139012552/shield)](https://styleci.io/repos/139012552)
-
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
-
[![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Framework+agnostic+Command+Line+Interface+utilities+and+helpers+for+PHP&url=https://github.com/adhocore/php-cli&hashtags=php,cli,cliapp,console)
-
[![Support](https://img.shields.io/static/v1?label=Support&message=%E2%9D%A4&logo=GitHub)](https://github.com/sponsors/adhocore)
-
<!-- [![Donate 15](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square&label=donate+15)](https://www.paypal.me/ji10/15usd)
-
[![Donate 25](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square&label=donate+25)](https://www.paypal.me/ji10/25usd)
-
[![Donate 50](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square&label=donate+50)](https://www.paypal.me/ji10/50usd) -->
-
-
-
- Command line application made easy
-
- Inspired by nodejs [commander](https://github.com/tj/commander.js) (thanks tj)
-
- Zero dependency.
-
- For PHP7, PHP8 and for good
-
-
[![Screen Preview](https://i.imgur.com/qIYg9Zn.gif "Preview from adhocore/phalcon-ext which uses this cli package")](https://github.com/adhocore/phalcon-ext/tree/master/example/cli)
-
-
#### What's included
-
-
**Core:** [Argv parser](#argv-parser) &middot; [Cli application](#console-app) &middot; [Shell](#shell)
-
-
**IO:** [Colorizer](#color) &middot; [Cursor manipulator](#cursor) &middot; [Progress bar](#progress-bar) &middot; [Stream writer](#writer) &middot; [Stream reader](#reader)
-
-
**Other:** [Autocompletion](#autocompletion)
-
-
## Installation
-
```bash
-
# PHP8.0 and above v1.0.0
-
composer require adhocore/cli:^v1.0.0
-
-
# PHP 7.x
-
composer require adhocore/cli:^v0.9.0
-
```
-
-
## Usage
-
-
### Argv parser
-
-
```php
-
$command = new Ahc\Cli\Input\Command('rmdir', 'Remove dirs');
-
-
$command
-
->version('0.0.1-dev')
-
// Arguments are separated by space
-
// Format: `<name>` for required, `[name]` for optional
-
// `[name:default]` for default value, `[name...]` for variadic (last argument)
-
->arguments('<dir> [dirs...]')
-
// `-h --help`, `-V --version`, `-v --verbosity` options are already added by default.
-
// Format: `<name>` for required, `[name]` for optional
-
->option('-s --with-subdir', 'Also delete subdirs (`with` means false by default)')
-
->option('-e,--no-empty', 'Delete empty (`no` means true by default)')
-
// Specify santitizer/callback as 3rd param, default value as 4th param
-
->option('-d|--depth [nestlevel]', 'How deep to process subdirs', 'intval', 5)
-
->parse(['thisfile.php', '-sev', 'dir', 'dir1', 'dir2', '-vv']) // `$_SERVER['argv']`
-
;
-
-
// Print all values:
-
print_r($command->values());
-
-
/*Array
-
(
-
[help] =>
-
[version] => 0.0.1
-
[verbosity] => 3
-
[dir] => dir
-
[dirs] => Array
-
(
-
[0] => dir1
-
[1] => dir2
-
)
-
-
[subdir] => true
-
[empty] => false
-
[depth] => 5
-
)*/
-
-
// To get values for options except the default ones (help, version, verbosity)
-
print_r($command->values(false));
-
-
// Pick a value by name
-
$command->dir; // dir
-
$command->dirs; // [dir1, dir2]
-
$command->depth; // 5
-
```
-
-
#### Command help
-
-
It can be triggered manually with `$command->showHelp()` or automatic when `-h` or `--help` option is passed to `$command->parse()`.
-
-
For above example, the output would be:
-
![Command Help](https://i.imgur.com/TDAQrN3.png "Command Help")
-
-
#### Command version
-
-
It can be triggered manually with `$command->showVersion()` or automatic when `-V` or `--version` option is passed to `$command->parse()`.
-
-
For above example, the output would be:
-
```
-
0.0.1-dev
-
```
-
-
### Console app
-
-
Definitely check [adhocore/phint](https://github.com/adhocore/phint) - a real world console application made using `adhocore/cli`.
-
-
Here we simulate a `git` app with limited functionality of `add`, and `checkout`.
-
You will see how intuitive, fluent and cheese building a console app is!
-
-
#### Git app
-
-
```php
-
$app = new Ahc\Cli\Application('git', '0.0.1');
-
-
$app
-
// Register `add` command
-
->command('add', 'Stage changed files', 'a') // alias a
-
// Set options and arguments for this command
-
->arguments('<path> [paths...]')
-
->option('-f --force', 'Force add ignored file', 'boolval', false)
-
->option('-N --intent-to-add', 'Add content later but index now', 'boolval', false)
-
// Handler for this command: param names should match but order can be anything :)
-
->action(function ($path, $paths, $force, $intentToAdd) {
-
array_unshift($paths, $path);
-
-
echo ($intentToAdd ? 'Intent to add ' : 'Add ')
-
. implode(', ', $paths)
-
. ($force ? ' with force' : '');
-
-
// If you return integer from here, that will be taken as exit error code
-
})
-
// Done setting up this command for now, tap() to retreat back so we can add another command
-
->tap()
-
->command('checkout', 'Switch branches', 'co') // alias co
-
->arguments('<branch>')
-
->option('-b --new-branch', 'Create a new branch and switch to it', false)
-
->option('-f --force', 'Checkout even if index differs', 'boolval', false)
-
->action(function ($branch, $newBranch, $force) {
-
echo 'Checkout to '
-
. ($newBranch ? 'new ' . $branch : $branch)
-
. ($force ? ' with force' : '');
-
})
-
;
-
-
// Parse only parses input but doesnt invoke action
-
$app->parse(['git', 'add', 'path1', 'path2', 'path3', '-f']);
-
-
// Handle will do both parse and invoke action.
-
$app->handle(['git', 'add', 'path1', 'path2', 'path3', '-f']);
-
// Will produce: Add path1, path2, path3 with force
-
-
$app->handle(['git', 'co', '-b', 'master-2', '-f']);
-
// Will produce: Checkout to new master-2 with force
-
```
-
-
### Organized app
-
-
Instead of inline commands/actions, we define and add our own commands (having `interact()` and `execute()`) to the app:
-
-
```php
-
class InitCommand extends Ahc\Cli\Input\Command
-
{
-
public function __construct()
-
{
-
parent::__construct('init', 'Init something');
-
-
$help = '<cyan>Custom help screen</end>';
-
$writer = new Ahc\Cli\Output\Writer();
-
-
$this
-
->argument('<arrg>', 'The Arrg')
-
->argument('[arg2]', 'The Arg2')
-
->option('-a --apple', 'The Apple')
-
->option('-b --ball', 'The ball')
-
->help($writer->colorizer()->colors($help))
-
// Usage examples:
-
->usage(
-
// append details or explanation of given example with ` ## ` so they will be uniformly aligned when shown
-
'<bold> init</end> <comment>--apple applet --ball ballon <arggg></end> ## details 1<eol/>' .
-
// $0 will be interpolated to actual command name
-
'<bold> $0</end> <comment>-a applet -b ballon <arggg> [arg2]</end> ## details 2<eol/>'
-
)
-
->logo('Ascii art logo of your command');
-
}
-
-
// This method is auto called before `self::execute()` and receives `Interactor $io` instance
-
public function interact(Ahc\Cli\IO\Interactor $io) : void
-
{
-
// Collect missing opts/args
-
if (!$this->apple) {
-
$this->set('apple', $io->prompt('Enter apple'));
-
}
-
-
if (!$this->ball) {
-
$this->set('ball', $io->prompt('Enter ball'));
-
}
-
-
// ...
-
}
-
-
// When app->handle() locates `init` command it automatically calls `execute()`
-
// with correct $ball and $apple values
-
public function execute($ball, $apple)
-
{
-
$io = $this->app()->io();
-
-
$io->write('Apple ' . $apple, true);
-
$io->write('Ball ' . $ball, true);
-
-
// more codes ...
-
-
// If you return integer from here, that will be taken as exit error code
-
}
-
}
-
-
class OtherCommand extends Ahc\Cli\Input\Command
-
{
-
public function __construct()
-
{
-
parent::__construct('other', 'Other something');
-
}
-
-
public function execute()
-
{
-
$io = $this->app()->io();
-
-
$io->write('Other command');
-
-
// more codes ...
-
-
// If you return integer from here, that will be taken as exit error code
-
}
-
}
-
-
// Init App with name and version
-
$app = new Ahc\Cli\Application('App', 'v0.0.1');
-
-
// Add commands with optional aliases`
-
$app->add(new InitCommand, 'i');
-
$app->add(new OtherCommand, 'o');
-
-
// Set logo
-
$app->logo('Ascii art logo of your app');
-
-
// Custom help screen
-
$app->help('Custom help screen (if omitted one will be generated)');
-
-
$app->handle($_SERVER['argv']); // if argv[1] is `i` or `init` it executes InitCommand
-
```
-
-
#### Grouping commands
-
-
Grouped commands are listed together in commands list. Explicit grouping a command is optional.
-
By default if a command name has a colon `:` then the part before it is taken as a group,
-
else `*` is taken as a group.
-
-
> Example: command name `app:env` has a default group `app`, command name `appenv` has group `*`.
-
-
```php
-
// Add grouped commands:
-
$app->group('Configuration', function ($app) {
-
$app->add(new ConfigSetCommand);
-
$app->add(new ConfigListCommand);
-
});
-
-
// Alternatively, set group one by one in each commands:
-
$app->add((new ConfigSetCommand)->inGroup('Config'));
-
$app->add((new ConfigListCommand)->inGroup('Config'));
-
...
-
```
-
-
#### Default command
-
-
By default, running your CLI app without any arguments will show the help screen. However you can set the default action to run one of your commands either by setting the third parameter of the `add` function to `true` or by using the `defaultCommand` function.
-
-
```php
-
$app->add(new InitCommand, 'i', true);
-
-
// Alternatively
-
$app->command('init', 'Init something', 'i');
-
$app->defaultCommand('init');
-
-
// Retrieve the name of the default command
-
$default_command = $app->getDefaultCommand();
-
```
-
-
#### Exception handler
-
-
Set a custom exception handler as callback. The callback receives exception & exit code. The callback may rethrow exception or may exit the program or just log exception and do nothing else.
-
-
```php
-
$app = new Ahc\Cli\Application('App', 'v0.0.1');
-
$app->add(...);
-
$app->onException(function (Throwable $e, int $exitCode) {
-
// send to sentry
-
// write to logs
-
-
// optionally, exit with exit code:
-
exit($exitCode);
-
-
// or optionally rethrow, a rethrown exception is propagated to top layer caller.
-
throw $e;
-
})->handle($argv);
-
```
-
-
#### App help
-
-
It can be triggered manually with `$app->showHelp()` or automatic when `-h` or `--help` option is passed to `$app->parse()`.
-
**Note** If you pass something like `['app', cmd', '-h']` to `$app->parse()` it will automatically and instantly show you help of that `cmd` and not the `$app`.
-
-
For above example, the output would be:
-
![App Help](https://i.imgur.com/NpzpsS0.png "App Help")
-
-
#### App version
-
-
Same version number is passed to all attached Commands. So you can trigger version on any of the commands.
-
-
### Shell
-
-
Very thin shell wrapper that provides convenience methods around `proc_open()`.
-
-
#### Basic usage
-
-
```php
-
$shell = new Ahc\Cli\Helper\Shell($command = 'php -v', $rawInput = null);
-
-
// Waits until proc finishes
-
$shell->execute($async = false); // default false
-
-
echo $shell->getOutput(); // PHP version string (often with zend/opcache info)
-
```
-
-
#### Advanced usage
-
-
```php
-
$shell = new Ahc\Cli\Helper\Shell('php /some/long/running/scipt.php');
-
-
// With async flag, doesnt wait for proc to finish!
-
$shell->setOptions($workDir = '/home', $envVars = [])
-
->execute($async = true)
-
->isRunning(); // true
-
-
// Force stop anytime (please check php.net/proc_close)
-
$shell->stop(); // also closes pipes
-
-
// Force kill anytime (please check php.net/proc_terminate)
-
$shell->kill();
-
```
-
-
#### Timeout
-
-
```php
-
$shell = new Ahc\Cli\Helper\Shell('php /some/long/running/scipt.php');
-
-
// Wait for at most 10.5 seconds for proc to finish!
-
// If it doesnt complete by then, throws exception
-
$shell->setOptions($workDir, $envVars, $timeout = 10.5)->execute();
-
-
// And if it completes within timeout, you can access the stdout/stderr
-
echo $shell->getOutput();
-
echo $shell->getErrorOutput();
-
```
-
-
### Cli Interaction
-
-
You can perform user interaction like printing colored output, reading user input programatically and moving the cursors around with provided `Ahc\Cli\IO\Interactor`.
-
-
```php
-
$interactor = new Ahc\Cli\IO\Interactor;
-
-
// For mocking io:
-
$interactor = new Ahc\Cli\IO\Interactor($inputPath, $outputPath);
-
```
-
-
#### Confirm
-
```php
-
$confirm = $interactor->confirm('Are you happy?', 'n'); // Default: n (no)
-
$confirm // is a boolean
-
? $interactor->greenBold('You are happy :)', true) // Output green bold text
-
: $interactor->redBold('You are sad :(', true); // Output red bold text
-
```
-
-
#### Single choice
-
```php
-
$fruits = ['a' => 'apple', 'b' => 'banana'];
-
$choice = $interactor->choice('Select a fruit', $fruits, 'b');
-
$interactor->greenBold("You selected: {$fruits[$choice]}", true);
-
```
-
-
#### Multiple choices
-
```php
-
$fruits = ['a' => 'apple', 'b' => 'banana', 'c' => 'cherry'];
-
$choices = $interactor->choices('Select fruit(s)', $fruits, ['b', 'c']);
-
$choices = \array_map(function ($c) use ($fruits) { return $fruits[$c]; }, $choices);
-
$interactor->greenBold('You selected: ' . implode(', ', $choices), true);
-
```
-
-
#### Prompt free input
-
```php
-
$any = $interactor->prompt('Anything', rand(1, 100)); // Random default
-
$interactor->greenBold("Anything is: $any", true);
-
```
-
-
#### Prompt with validation
-
```php
-
$nameValidator = function ($value) {
-
if (\strlen($value) < 5) {
-
throw new \InvalidArgumentException('Name should be atleast 5 chars');
-
}
-
-
return $value;
-
};
-
-
// No default, Retry 5 more times
-
$name = $interactor->prompt('Name', null, $nameValidator, 5);
-
$interactor->greenBold("The name is: $name", true);
-
```
-
-
#### Prompt hidden
-
-
> On windows platform, it may change the fontface which can be [fixed](https://superuser.com/a/757591).
-
-
```php
-
$passValidator = function ($pass) {
-
if (\strlen($pass) < 6) {
-
throw new \InvalidArgumentException('Password too short');
-
}
-
-
return $pass;
-
};
-
-
$pass = $interactor->promptHidden('Password', $passValidator, 2);
-
```
-
-
![Interactive Preview](https://i.imgur.com/qYBNd29.gif "Interactive Preview")
-
-
## IO Components
-
-
The interactor is composed of `Ahc\Cli\Input\Reader` and `Ahc\Cli\Output\Writer` while the `Writer` itself is composed of `Ahc\Cli\Output\Color`. All these components can be used standalone.
-
-
### Color
-
-
Color looks cool!
-
-
```php
-
$color = new Ahc\Cli\Output\Color;
-
```
-
-
#### Simple usage
-
-
```php
-
echo $color->warn('This is warning');
-
echo $color->info('This is info');
-
echo $color->error('This is error');
-
echo $color->comment('This is comment');
-
echo $color->ok('This is ok msg');
-
```
-
-
#### Custom style
-
```php
-
Ahc\Cli\Output\Color::style('mystyle', [
-
'bg' => Ahc\Cli\Output\Color::CYAN,
-
'fg' => Ahc\Cli\Output\Color::fg256(57), // 256 colors can be used as well
-
'bold' => 1, // You can experiment with 0, 1, 2, 3 ... as well
-
]);
-
-
echo $color->mystyle('My text');
-
```
-
-
#### Built-in styles
-
-
There are a number of pre-defined built-in styles that allows you granular customization to different output conditions such as help and prompts:
-
-
- answer
-
- choice
-
- comment
-
- error
-
- help_category
-
- help_description_even
-
- help_description_odd
-
- help_example
-
- help_footer
-
- help_group
-
- help_header
-
- help_item_even
-
- help_item_odd
-
- help_summary
-
- help_text
-
- info
-
- logo
-
- ok
-
- question
-
- version
-
- warn
-
-
Overriding a built-in style works the same way as defining a new style:
-
-
```php
-
Ahc\Cli\Output\Color::style('error', [
-
'fg' => Ahc\Cli\Output\Color::RED,
-
'bold' => 1,
-
]);
-
```
-
-
#### Disable colors
-
-
```php
-
Ahc\Cli\Output\Color::$enabled = false;
-
```
-
-
Colors will be automatically disabled if the `NO_COLOR` environment variable is set to true.
-
-
### Cursor
-
-
Move cursor around, erase line up or down, clear screen.
-
-
```php
-
$cursor = new Ahc\Cli\Output\Cursor;
-
-
echo $cursor->up(1)
-
. $cursor->down(2)
-
. $cursor->right(3)
-
. $cursor->left(4)
-
. $cursor->next(0)
-
. $cursor->prev(2);
-
. $cursor->eraseLine()
-
. $cursor->clear()
-
. $cursor->clearUp()
-
. $cursor->clearDown()
-
. $cursor->moveTo(5, 8); // x, y
-
```
-
-
### Progress Bar
-
-
Easily add a progress bar to your output:
-
-
```php
-
$progress = new Ahc\Cli\Output\ProgressBar(100);
-
for ($i = 0; $i <= 100; $i++) {
-
$progress->current($i);
-
-
// Simulate something happening
-
usleep(80000);
-
}
-
```
-
-
You can also manually advance the bar:
-
-
```php
-
$progress = new Ahc\Cli\Output\ProgressBar(100);
-
-
// Do something
-
-
$progress->advance(); // Adds 1 to the current progress
-
-
// Do something
-
-
$progress->advance(10); // Adds 10 to the current progress
-
-
// Do something
-
-
$progress->advance(5, 'Still going.'); // Adds 5, displays a label
-
```
-
-
You can override the progress bar options to customize it to your liking:
-
-
```php
-
$progress = new Ahc\Cli\Output\ProgressBar(100);
-
$progress->option('pointer', '>>');
-
$progress->option('loader', '▩');
-
-
// You can set the progress fluently
-
$progress->option('pointer', '>>')->option('loader', '▩');
-
-
// You can also use an associative array to set many options in one time
-
$progress->option([
-
'pointer' => '>>',
-
'loader' => '▩'
-
]);
-
-
// Available options
-
+---------------+------------------------------------------------------+---------------+
-
| Option | Description | Default value |
-
+===============+======================================================+===============+
-
| pointer | The progress bar head symbol | > |
-
| loader | The loader symbol | = |
-
| color | The color of progress bar | white |
-
| labelColor | The text color of the label | white |
-
| labelPosition | The position of the label (top, bottom, left, right) | bottom |
-
+---------------+------------------------------------------------------+---------------+
-
-
```
-
-
### Writer
-
-
Write anything in style.
-
-
```php
-
$writer = new Ahc\Cli\Output\Writer;
-
-
// All writes are forwarded to STDOUT
-
// But if you specify error, then to STDERR
-
$writer->errorBold('This is error');
-
```
-
-
#### Output formatting
-
-
You can call methods composed of any combinations:
-
`'<colorName>', 'bold', 'bg', 'fg', 'warn', 'info', 'error', 'ok', 'comment'`
-
... in any order (eg: `bgRedFgBlaock`, `boldRed`, `greenBold`, `commentBgPurple` and so on ...)
-
-
```php
-
$writer->bold->green->write('It is bold green');
-
$writer->boldGreen('It is bold green'); // Same as above
-
$writer->comment('This is grayish comment', true); // True indicates append EOL character.
-
$writer->bgPurpleBold('This is white on purple background');
-
```
-
-
#### Free style
-
-
Many colors with one single call: wrap text with tags `<method>` and `</end>`
-
For NL/EOL just use `<eol>` or `</eol>` or `<eol/>`.
-
-
Great for writing long colorful texts for example command usage info.
-
-
```php
-
$writer->colors('<red>This is red</end><eol><bgGreen>This has bg Green</end>');
-
```
-
-
#### Raw output
-
-
```php
-
$writer->raw('Enter name: ');
-
```
-
-
#### Tables
-
-
Just pass array of assoc arrays. The keys of first array will be taken as heading.
-
Heading is auto inflected to human readable capitalized words (ucwords).
-
-
```php
-
$writer->table([
-
['a' => 'apple', 'b-c' => 'ball', 'c_d' => 'cat'],
-
['a' => 'applet', 'b-c' => 'bee', 'c_d' => 'cute'],
-
]);
-
```
-
-
Gives something like:
-
-
```
-
+--------+------+------+
-
| A | B C | C D |
-
+--------+------+------+
-
| apple | ball | cat |
-
| applet | bee | cute |
-
+--------+------+------+
-
```
-
-
> Designing table look and feel
-
-
Just pass 2nd param `$styles`:
-
-
```php
-
$writer->table([
-
['a' => 'apple', 'b-c' => 'ball', 'c_d' => 'cat'],
-
['a' => 'applet', 'b-c' => 'bee', 'c_d' => 'cute'],
-
], [
-
// for => styleName (anything that you would call in $writer instance)
-
'head' => 'boldGreen', // For the table heading
-
'odd' => 'bold', // For the odd rows (1st row is odd, then 3, 5 etc)
-
'even' => 'comment', // For the even rows (2nd row is even, then 4, 6 etc)
-
'1:1' => 'red', // For cell in row 1 col 1 (1 based count, 'apple' in this example)
-
'2:*' => '', // For all cells in row 2 (1 based count)
-
'*:2' => '', // For all cells in col 2 (1 based count)
-
'b-c' => '', // For all columns named 'b-c' (same as '*:2' in this example)
-
'*:*' => 'blue', // For all cells in table (Set all cells to blue)
-
]);
-
```
-
-
You can define the style of a cell dynamically using a callback. You could then apply one style or another depending on a value.
-
-
```php
-
$rows = [
-
['name' => 'John Doe', 'age' => '30'],
-
['name' => 'Jane Smith', 'age' => '25'],
-
['name' => 'Bob Johnson', 'age' => '40'],
-
];
-
-
$styles = [
-
'*:2' => function ($val, $row) {
-
return $row['age'] >= 30 ? 'boldRed' : '';
-
},
-
];
-
-
$writer->table($rows, $styles);
-
```
-
-
The example above only processes the cells in the second column of the table. If you want to process any cell, you can use the `*:*` key. You could then customise each cell in the table
-
-
```php
-
$rows = [
-
['name' => 'John Doe', 'age' => '30'],
-
['name' => 'Jane Smith', 'age' => '25'],
-
['name' => 'Alice Bob', 'age' => '10'],
-
['name' => 'Big Johnson', 'age' => '40'],
-
['name' => 'Jane X', 'age' => '50'],
-
['name' => 'John Smith', 'age' => '20'],
-
['name' => 'Bob John', 'age' => '28'],
-
];
-
-
$styles = [
-
'*:*' => function ($val, $row) {
-
if ($val === 'Jane X') {
-
return 'yellow';
-
}
-
if ($val == 10 || $val == 20) {
-
return 'boldPurple';
-
}
-
if (str_contains($val, 'Bob')) {
-
return 'blue';
-
}
-
return $row['age'] >= 30 ? 'boldRed' : '';
-
},
-
];
-
-
$writer->table($rows, $styles);
-
```
-
-
> **Note: Priority in increasing order:**
-
> - `odd` or `even`
-
> - `2:*` (row)
-
> - `*:2` or `b-c <-> column name` (col)
-
> - `*:*` any cell in table
-
> - `1:1` (cell) = **highest priority**
-
-
#### Justify content (Display setting)
-
-
If you want to display certain configurations (from your .env file for example) a bit like Laravel does (via the `php artisan about` command) you can use the `justify` method.
-
-
```php
-
$writer->justify('Environment');
-
$writer->justify('PHP Version', PHP_VERSION);
-
$writer->justify('App Version', '1.0.0');
-
$writer->justify('Locale', 'en');
-
```
-
-
Gives something like:
-
-
```
-
Environment ........................................
-
PHP Version .................................. 8.1.4
-
App Version .................................. 1.0.0
-
Locale .......................................... en
-
```
-
-
You can use the `sep` parameter to define the separator to use.
-
-
```php
-
$writer->justify('Environment', '', ['sep' => '-']);
-
$writer->justify('PHP Version', PHP_VERSION);
-
```
-
-
Gives something like:
-
-
```
-
Environment ----------------------------------------
-
PHP Version .................................. 8.1.4
-
```
-
-
In addition, the text color, the background color and the thickness of the two texts can be defined via the 3rd argument of this method.
-
-
```php
-
$writer->justify('Cache Enable', 'true', [
-
'first' => ['fg' => Ahc\Cli\Output\Color::CYAN], // style of the key
-
'second' => ['fg' => Ahc\Cli\Output\Color::GREEN], // style of the value
-
]);
-
$writer->justify('Debug Mode', 'false', [
-
'first' => ['fg' => Ahc\Cli\Output\Color::CYAN], // style of the key
-
'second' => ['fg' => Ahc\Cli\Output\Color::RED], // style of the value
-
]);
-
```
-
-
For more details regarding the different color options, see [Custom style](#custom-style)
-
-
#### Reader
-
-
Read and pre process user input.
-
-
```php
-
$reader = new Ahc\Cli\Input\Reader;
-
-
// No default, callback fn `ucwords()`
-
$reader->read(null, 'ucwords');
-
-
// Default 'abc', callback `trim()`
-
$reader->read('abc', 'trim');
-
-
// Read at most first 5 chars
-
// (if ENTER is pressed before 5 chars then further read is aborted)
-
$reader->read('', 'trim', 5);
-
-
// Read but dont echo back the input
-
$reader->readHidden($default, $callback);
-
-
// Read from piped stream (or STDIN) if available without waiting
-
$reader->readPiped();
-
-
// Pass in a callback for if STDIN is empty
-
// The callback recieves $reader instance and MUST return string
-
$reader->readPiped(function ($reader) {
-
// Wait to read a line!
-
return $reader->read();
-
-
// Wait to read multi lines (until Ctrl+D pressed)
-
return $reader->readAll();
-
});
-
```
-
-
#### Exceptions
-
-
Whenever an exception is caught by `Application::handle()`, it will show a beautiful stack trace and exit with non 0 status code.
-
-
![Exception Preview](https://user-images.githubusercontent.com/2908547/44401057-8b350880-a577-11e8-8ca6-20508d593d98.png "Exception trace")
-
-
## I18n Support
-
-
**adhocore/cli** also supports internationalisation. This is particularly useful if you are not very comfortable with English or if you are creating a framework or CLI application that could be used by people from a variety of backgrounds.
-
-
By default, all the texts generated by our system are in English. But you can easily modify them by defining your translations as follows
-
-
```php
-
\Ahc\Application::addLocale('fr', [
-
'Only last argument can be variadic' => 'Seul le dernier argument peut être variadique',
-
], true);
-
```
-
-
You can also change the default English text to make the description more explicit if you wish.
-
-
```php
-
\Ahc\Application::addLocale('en', [
-
'Show help' => 'Shows helpful information about a command',
-
]);
-
```
-
-
you can find all the translation keys supported by the package in this gist : https://gist.github.com/dimtrovich/1597c16d5c74334e68eef15a4e7ba3fd
-
-
## Autocompletion
-
-
Any console applications that are built on top of **adhocore/cli** can entertain autocomplete of commands and options in zsh shell with oh-my-zsh.
-
-
All you have to do is add one line to the end of `~/.oh-my-zsh/custom/plugins/ahccli/ahccli.plugin.zsh`:
-
-
> `compdef _ahccli <appname>`
-
-
Example: `compdef _ahccli phint` for [phint](https://github.com/adhocore/phint).
-
-
That is cumbersome to perform manually, here's a complete command you can copy/paste/run:
-
-
#### One time setup
-
-
```sh
-
mkdir -p ~/.oh-my-zsh/custom/plugins/ahccli && cd ~/.oh-my-zsh/custom/plugins/ahccli
-
-
[ -f ./ahccli.plugin.zsh ] || curl -sSLo ./ahccli.plugin.zsh https://raw.githubusercontent.com/adhocore/php-cli/master/ahccli.plugin.zsh
-
-
chmod 760 ./ahccli.plugin.zsh && cd -
-
```
-
-
##### Load ahccli plugin
-
-
> This is also one time setup.
-
-
```sh
-
# Open .zshrc
-
nano ~/.zshrc
-
-
# locate plugins=(... ...) and add ahccli
-
plugins=(git ... ... ahccli)
-
-
# ... then save it (Ctrl + O)
-
```
-
-
#### Registering app
-
-
```sh
-
# replace appname with real name eg: phint
-
echo compdef _ahccli appname >> ~/.oh-my-zsh/custom/plugins/ahccli/ahccli.plugin.zsh
-
```
-
-
> Of course you can add multiple apps, just change appname in above command
-
-
Then either restart the shell or source the plugin like so:
-
-
```sh
-
source ~/.oh-my-zsh/custom/plugins/ahccli/ahccli.plugin.zsh
-
```
-
-
#### Trigger autocomplete
-
-
```sh
-
appname <tab> # autocompletes commands (phint <tab>)
-
appname subcommand <tab> # autocompletes options for subcommand (phint init <tab>)
-
```
-
-
### Related
-
-
- [adhocore/phalcon-ext](https://github.com/adhocore/phalcon-ext) &middot; Phalcon extension using `adhocore/cli`
-
- [adhocore/phint](https://github.com/adhocore/phint) &middot; PHP project scaffolding app using `adhocore/cli`
-
- [adhocore/type-hinter](https://github.com/adhocore/php-type-hinter) &middot; Auto PHP7 typehinter tool using `adhocore/cli`
-
-
### Contributors
-
-
- [adhocore](https://github.com/adhocore)
-
- [sushilgupta](https://github.com/sushilgupta)
-
-
## License
-
-
> &copy; 2017-2020, [Jitendra Adhikari](https://github.com/adhocore) | [MIT](./LICENSE)
-
-
### Credits
-
-
This project is release managed by [please](https://github.com/adhocore/please).
-1
vendor/adhocore/cli/VERSION
···
-
v1.2.0
-54
vendor/adhocore/cli/composer.json
···
-
{
-
"name": "adhocore/cli",
-
"description": "Command line interface library for PHP",
-
"type": "library",
-
"keywords": [
-
"php8",
-
"command",
-
"argv-parser",
-
"cli",
-
"cli-color",
-
"cli-action",
-
"console",
-
"cli-writer",
-
"argument-parser",
-
"cli-option",
-
"stream-output",
-
"stream-input",
-
"cli-app",
-
"console-app",
-
"php-cli"
-
],
-
"license": "MIT",
-
"authors": [
-
{
-
"name": "Jitendra Adhikari",
-
"email": "jiten.adhikary@gmail.com"
-
}
-
],
-
"autoload": {
-
"psr-4": {
-
"Ahc\\Cli\\": "src/"
-
},
-
"files": [
-
"src/functions.php"
-
]
-
},
-
"autoload-dev": {
-
"psr-4": {
-
"Ahc\\Cli\\Test\\": "tests/"
-
}
-
},
-
"require": {
-
"php": ">=8.0"
-
},
-
"require-dev": {
-
"phpunit/phpunit": "^9.0"
-
},
-
"scripts": {
-
"test": "phpunit",
-
"test:cov": "phpunit --coverage-text --coverage-clover coverage.xml --coverage-html vendor/cov",
-
"cs:sniff": "tools/phpcs",
-
"cs:fix": "tools/phpcbf"
-
}
-
}
-480
vendor/adhocore/cli/src/Application.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli;
-
-
use Ahc\Cli\Exception\InvalidArgumentException;
-
use Ahc\Cli\Helper\OutputHelper;
-
use Ahc\Cli\Input\Command;
-
use Ahc\Cli\IO\Interactor;
-
use ReflectionClass;
-
use ReflectionFunction;
-
use Throwable;
-
-
use function array_diff_key;
-
use function array_fill_keys;
-
use function array_keys;
-
use function count;
-
use function func_num_args;
-
use function in_array;
-
use function is_array;
-
use function is_int;
-
use function method_exists;
-
-
/**
-
* A cli application.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
class Application
-
{
-
/**
-
* Locale of CLI.
-
*/
-
public static $locale = 'en';
-
-
/**
-
* list of translations for each supported locale.
-
*
-
* @var array<string, array>
-
*
-
* @example
-
* ```php
-
* ['locale' => ['key1' => 'value1', 'key2' => 'value2']]
-
* ```
-
*/
-
public static $locales = [];
-
-
/** @var Command[] */
-
protected array $commands = [];
-
-
/** @var array Raw argv sent to parse() */
-
protected array $argv = [];
-
-
/** @var array Command aliases [alias => cmd] */
-
protected array $aliases = [];
-
-
/** @var string Ascii art logo */
-
protected string $logo = '';
-
-
/** @var string Custom help screen */
-
protected string $help = '';
-
-
/** @var string Name of default command */
-
protected string $default = '__default__';
-
-
/** @var null|Interactor */
-
protected ?Interactor $io = null;
-
-
/** @var callable The callable to perform exit */
-
protected $onExit;
-
-
/** @var callable The callable to catch exception, receives exception & exit code, may rethrow exception or may exit program */
-
protected $onException = null;
-
-
public function __construct(protected string $name, protected string $version = '0.0.1', ?callable $onExit = null)
-
{
-
$this->onExit = $onExit ?? static fn (int $exitCode = 0) => exit($exitCode);
-
-
$this->command('__default__', 'Default command', '', true)->on([$this, 'showHelp'], 'help');
-
}
-
-
/**
-
* Get the name.
-
*/
-
public function name(): string
-
{
-
return $this->name;
-
}
-
-
/**
-
* Get the version.
-
*/
-
public function version(): string
-
{
-
return $this->version;
-
}
-
-
/**
-
* Get the commands.
-
*
-
* @return Command[]
-
*/
-
public function commands(): array
-
{
-
$commands = $this->commands;
-
-
unset($commands['__default__']);
-
-
return $commands;
-
}
-
-
/**
-
* Get the raw argv.
-
*/
-
public function argv(): array
-
{
-
return $this->argv;
-
}
-
-
/**
-
* Sets or gets the ASCII art logo.
-
*
-
* @param string|null $logo
-
*
-
* @return string|self
-
*/
-
public function logo(?string $logo = null)
-
{
-
if (func_num_args() === 0) {
-
return $this->logo;
-
}
-
-
$this->logo = $logo;
-
-
return $this;
-
}
-
-
public static function addLocale(string $locale, array $texts, bool $default = false)
-
{
-
if ($default) {
-
self::$locale = $locale;
-
}
-
-
self::$locales[$locale] = $texts;
-
}
-
-
/**
-
* Add a command by its name desc alias etc and return command.
-
*/
-
public function command(
-
string $name,
-
string $desc = '',
-
string $alias = '',
-
bool $allowUnknown = false,
-
bool $default = false
-
): Command {
-
$command = new Command($name, $desc, $allowUnknown, $this);
-
-
$this->add($command, $alias, $default);
-
-
return $command;
-
}
-
-
/**
-
* Add a prepared command and return itself.
-
*/
-
public function add(Command $command, string $alias = '', bool $default = false): self
-
{
-
$name = $command->name();
-
-
if (
-
$this->commands[$name] ??
-
$this->aliases[$name] ??
-
$this->commands[$alias] ??
-
$this->aliases[$alias] ??
-
null
-
) {
-
throw new InvalidArgumentException(t('Command "%s" already added', [$name]));
-
}
-
-
if ($alias) {
-
$command->alias($alias);
-
$this->aliases[$alias] = $name;
-
}
-
-
if ($default) {
-
$this->default = $name;
-
}
-
-
$this->commands[$name] = $command->version($this->version)->onExit($this->onExit)->bind($this);
-
-
return $this;
-
}
-
-
/**
-
* Set the default command.
-
*
-
* @param string $commandName The name of the default command
-
*
-
* @throws InvalidArgumentException If the specified command name does not exist
-
*
-
* @return self The application
-
*/
-
public function defaultCommand(string $commandName): self
-
{
-
if (!isset($this->commands[$commandName])) {
-
throw new InvalidArgumentException(t('Command "%s" does not exist', [$commandName]));
-
}
-
-
$this->default = $commandName;
-
-
return $this;
-
}
-
-
/**
-
* Get the default command.
-
*
-
* @return string|null The name of the default command, or null if not set
-
*/
-
public function getDefaultCommand(): ?string
-
{
-
return $this->default;
-
}
-
-
/**
-
* Groups commands set within the callable.
-
*
-
* @param string $group The group name
-
* @param callable $fn The callable that recieves Application instance and adds commands.
-
*
-
* @return self
-
*/
-
public function group(string $group, callable $fn): self
-
{
-
$old = array_fill_keys(array_keys($this->commands), true);
-
-
$fn($this);
-
foreach (array_diff_key($this->commands, $old) as $cmd) {
-
$cmd->inGroup($group);
-
}
-
-
return $this;
-
}
-
-
/**
-
* Gets matching command for given argv.
-
*/
-
public function commandFor(array $argv): Command
-
{
-
$argv += [null, null, null];
-
-
return
-
// cmd
-
$this->commands[$argv[1]]
-
// cmd alias
-
?? $this->commands[$this->aliases[$argv[1]] ?? null]
-
// default.
-
?? $this->commands[$this->default];
-
}
-
-
/**
-
* Gets or sets io.
-
*
-
* @param Interactor|null $io
-
*
-
* @return Interactor|self
-
*/
-
public function io(?Interactor $io = null)
-
{
-
if ($io || !$this->io) {
-
$this->io = $io ?? new Interactor;
-
}
-
-
if (func_num_args() === 0) {
-
return $this->io;
-
}
-
-
return $this;
-
}
-
-
/**
-
* Parse the arguments via the matching command but dont execute action..
-
*
-
* @param array $argv Cli arguments/options.
-
*
-
* @return Command The matched and parsed command (or default)
-
*/
-
public function parse(array $argv): Command
-
{
-
$this->argv = $argv;
-
-
$command = $this->commandFor($argv);
-
$aliases = $this->aliasesFor($command);
-
-
// Eat the cmd name!
-
foreach ($argv as $i => $arg) {
-
if (in_array($arg, $aliases)) {
-
unset($argv[$i]);
-
-
break;
-
}
-
-
if ($arg[0] === '-') {
-
break;
-
}
-
}
-
-
return $command->parse($argv);
-
}
-
-
/**
-
* Sets exception handler callback.
-
*
-
* The callback receives exception & exit code. It may rethrow exception
-
* or may exit the program or just log exception and do nothing else.
-
*/
-
public function onException(callable $fn): self
-
{
-
$this->onException = $fn;
-
-
return $this;
-
}
-
-
/**
-
* Handle the request, invoke action and call exit handler.
-
*/
-
public function handle(array $argv): mixed
-
{
-
if ($this->default === '__default__' && count($argv) < 2) {
-
return $this->showHelp();
-
}
-
-
$exitCode = 255;
-
-
try {
-
$command = $this->parse($argv);
-
$result = $this->doAction($command);
-
$exitCode = is_int($result) ? $result : 0;
-
} catch (Throwable $e) {
-
isset($this->onException) && ($this->onException)($e, $exitCode);
-
$this->outputHelper()->printTrace($e);
-
}
-
-
return ($this->onExit)($exitCode);
-
}
-
-
/**
-
* Get aliases for given command.
-
*/
-
protected function aliasesFor(Command $command): array
-
{
-
$aliases = [$name = $command->name()];
-
-
foreach ($this->aliases as $alias => $cmd) {
-
if (in_array($name, [$alias, $cmd], true)) {
-
$aliases[] = $alias;
-
$aliases[] = $cmd;
-
}
-
}
-
-
return $aliases;
-
}
-
-
/**
-
* Sets or gets the custom help screen contents.
-
*
-
* @param string|null $help
-
*
-
* @return string|self
-
*/
-
public function help(?string $help = null): mixed
-
{
-
if (func_num_args() === 0) {
-
return $this->help;
-
}
-
-
$this->help = $help;
-
-
return $this;
-
}
-
-
/**
-
* Show custom help screen if one is set, otherwise shows the default one.
-
*/
-
public function showHelp(): mixed
-
{
-
if ($help = $this->help()) {
-
$writer = $this->io()->writer();
-
$writer->write($help, true);
-
-
return ($this->onExit)();
-
}
-
-
return $this->showDefaultHelp();
-
}
-
-
/**
-
* Shows command help then aborts.
-
*/
-
public function showDefaultHelp(): mixed
-
{
-
$writer = $this->io()->writer();
-
$header = "{$this->name}, " . t('version') . " {$this->version}";
-
$footer = t('Run `<command> --help` for specific help');
-
-
if ($this->logo) {
-
$writer->logo($this->logo, true);
-
}
-
-
$this->outputHelper()->showCommandsHelp($this->commands(), $header, $footer);
-
-
return ($this->onExit)();
-
}
-
-
protected function outputHelper(): OutputHelper
-
{
-
$writer = $this->io()->writer();
-
-
return new OutputHelper($writer);
-
}
-
-
/**
-
* Invoke command action.
-
*/
-
protected function doAction(Command $command): mixed
-
{
-
if ($command->name() === '__default__') {
-
return $this->notFound();
-
}
-
-
// Let the command collect more data (if missing or needs confirmation)
-
$command->interact($this->io());
-
-
if (!$command->action() && !method_exists($command, 'execute')) {
-
return null;
-
}
-
-
$params = [];
-
$values = $command->values();
-
// We prioritize action to be in line with commander.js!
-
$action = $command->action() ?? [$command, 'execute'];
-
-
foreach ($this->getActionParameters($action) as $param) {
-
$params[] = $values[$param->getName()] ?? null;
-
}
-
-
return $action(...$params);
-
}
-
-
/**
-
* Command not found handler.
-
*/
-
protected function notFound(): mixed
-
{
-
$available = array_keys($this->commands() + $this->aliases);
-
$this->outputHelper()->showCommandNotFound($this->argv[1], $available);
-
-
return ($this->onExit)(127);
-
}
-
-
protected function getActionParameters(callable $action): array
-
{
-
$reflex = is_array($action)
-
? (new ReflectionClass($action[0]))->getMethod($action[1])
-
: new ReflectionFunction($action);
-
-
return $reflex->getParameters();
-
}
-
}
-19
vendor/adhocore/cli/src/Exception.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli;
-
-
use Throwable;
-
-
interface Exception extends Throwable
-
{
-
// ;)
-
}
-19
vendor/adhocore/cli/src/Exception/InvalidArgumentException.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Exception;
-
-
use Ahc\Cli\Exception;
-
-
class InvalidArgumentException extends \InvalidArgumentException implements Exception
-
{
-
// ;)
-
}
-17
vendor/adhocore/cli/src/Exception/InvalidParameterException.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Exception;
-
-
class InvalidParameterException extends InvalidArgumentException
-
{
-
// ;)
-
}
-19
vendor/adhocore/cli/src/Exception/RuntimeException.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Exception;
-
-
use Ahc\Cli\Exception;
-
-
class RuntimeException extends \RuntimeException implements Exception
-
{
-
// ;)
-
}
-78
vendor/adhocore/cli/src/Helper/InflectsString.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Helper;
-
-
use function lcfirst;
-
use function mb_strwidth;
-
use function mb_substr;
-
use function str_replace;
-
use function strlen;
-
use function substr;
-
use function trim;
-
use function ucwords;
-
-
/**
-
* Performs inflection on strings.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
trait InflectsString
-
{
-
/**
-
* Convert a string to camel case.
-
*/
-
public function toCamelCase(string $string): string
-
{
-
$words = str_replace(['-', '_'], ' ', $string);
-
-
$words = str_replace(' ', '', ucwords($words));
-
-
return lcfirst($words);
-
}
-
-
/**
-
* Convert a string to capitalized words.
-
*/
-
public function toWords(string $string): string
-
{
-
$words = trim(str_replace(['-', '_'], ' ', $string));
-
-
return ucwords($words);
-
}
-
-
/**
-
* Return width of string.
-
*/
-
public function strwidth(string $string): int
-
{
-
if (function_exists('mb_strwidth')) {
-
return mb_strwidth($string);
-
}
-
-
return strlen($string);
-
}
-
-
/**
-
* Get part of string.
-
*/
-
public function substr(string $string, int $start, ?int $length = null): string
-
{
-
if (function_exists('mb_substr')) {
-
return mb_substr($string, $start, $length);
-
}
-
-
return substr($string, $start, $length);
-
}
-
}
-76
vendor/adhocore/cli/src/Helper/Normalizer.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Helper;
-
-
use Ahc\Cli\Input\Option;
-
use Ahc\Cli\Input\Parameter;
-
-
use function array_merge;
-
use function explode;
-
use function implode;
-
use function ltrim;
-
use function preg_match;
-
use function str_split;
-
-
/**
-
* Internal value &/or argument normalizer. Has little to no usefulness as public api.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
class Normalizer
-
{
-
/**
-
* Normalize argv args. Like splitting `-abc` and `--xyz=...`.
-
*/
-
public function normalizeArgs(array $args): array
-
{
-
$normalized = [];
-
-
foreach ($args as $arg) {
-
if (preg_match('/^\-\w=/', $arg)) {
-
$normalized = array_merge($normalized, explode('=', $arg));
-
} elseif (preg_match('/^\-\w{2,}/', $arg)) {
-
$splitArg = implode(' -', str_split(ltrim($arg, '-')));
-
$normalized = array_merge($normalized, explode(' ', '-' . $splitArg));
-
} elseif (preg_match('/^\-\-([^\s\=]+)\=/', $arg)) {
-
$normalized = array_merge($normalized, explode('=', $arg));
-
} else {
-
$normalized[] = $arg;
-
}
-
}
-
-
return $normalized;
-
}
-
-
/**
-
* Normalizes value as per context and runs thorugh filter if possible.
-
*/
-
public function normalizeValue(Parameter $parameter, ?string $value = null): mixed
-
{
-
if ($parameter instanceof Option && $parameter->bool()) {
-
return !$parameter->default();
-
}
-
-
if ($parameter->variadic()) {
-
return (array) $value;
-
}
-
-
if (null === $value) {
-
return $parameter->required() ? null : true;
-
}
-
-
return $parameter->filter($value);
-
}
-
}
-387
vendor/adhocore/cli/src/Helper/OutputHelper.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Helper;
-
-
use Ahc\Cli\Exception;
-
use Ahc\Cli\Input\Argument;
-
use Ahc\Cli\Input\Command;
-
use Ahc\Cli\Input\Groupable;
-
use Ahc\Cli\Input\Option;
-
use Ahc\Cli\Input\Parameter;
-
use Ahc\Cli\Output\Writer;
-
use Throwable;
-
-
use function Ahc\Cli\t;
-
use function array_map;
-
use function array_shift;
-
use function asort;
-
use function explode;
-
use function get_class;
-
use function gettype;
-
use function implode;
-
use function is_array;
-
use function is_object;
-
use function is_scalar;
-
use function key;
-
use function levenshtein;
-
use function max;
-
use function method_exists;
-
use function preg_replace;
-
use function preg_replace_callback;
-
use function realpath;
-
use function str_contains;
-
use function str_pad;
-
use function str_replace;
-
use function strlen;
-
use function strrpos;
-
use function trim;
-
use function uasort;
-
use function var_export;
-
-
use const STR_PAD_LEFT;
-
-
/**
-
* This helper helps you by showing you help information :).
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
class OutputHelper
-
{
-
use InflectsString;
-
-
/**
-
* The output writer instance used to write formatted output.
-
*
-
* @var Writer
-
*/
-
protected Writer $writer;
-
/**
-
* Max width of command name.
-
*
-
* @var int
-
*/
-
protected int $maxCmdName = 0;
-
-
/**
-
* Class constructor.
-
*
-
* @param Writer|null $writer The output writer instance used to write formatted output.
-
*/
-
public function __construct(?Writer $writer = null)
-
{
-
$this->writer = $writer ?? new Writer;
-
}
-
-
/**
-
* Print stack trace and error msg of an exception.
-
*/
-
public function printTrace(Throwable $e): void
-
{
-
$eClass = get_class($e);
-
-
$this->writer->colors(
-
"$eClass <red>{$e->getMessage()}</end><eol/>" .
-
'(' . t('thrown in') . " <yellow>{$e->getFile()}</end><white>:{$e->getLine()})</end>"
-
);
-
-
// @codeCoverageIgnoreStart
-
if ($e instanceof Exception) {
-
// Internal exception traces are not printed.
-
return;
-
}
-
// @codeCoverageIgnoreEnd
-
-
$traceStr = '<eol/><eol/><bold>' . t('Stack Trace') . ':</end><eol/><eol/>';
-
-
foreach ($e->getTrace() as $i => $trace) {
-
$trace += ['class' => '', 'type' => '', 'function' => '', 'file' => '', 'line' => '', 'args' => []];
-
$symbol = $trace['class'] . $trace['type'] . $trace['function'];
-
$args = $this->stringifyArgs($trace['args']);
-
-
$traceStr .= " <comment>$i)</end> <red>$symbol</end><comment>($args)</end>";
-
if ('' !== $trace['file']) {
-
$file = realpath($trace['file']);
-
$traceStr .= '<eol/> <yellow>' . t('at') . " $file</end><white>:{$trace['line']}</end><eol/>";
-
}
-
}
-
-
$this->writer->colors($traceStr);
-
}
-
-
/**
-
* Converts an array of arguments into a string representation.
-
*
-
* Each array element is converted based on its type:
-
* - Scalar values (int, float, string, bool) are var_exported
-
* - Objects are converted using __toString() if available, otherwise class name is used
-
* - Arrays are recursively processed and wrapped in square brackets
-
* - Other types are converted to their type name
-
*
-
* @param array $args Array of arguments to be stringified
-
*
-
* @return string The comma-separated string representation of all arguments
-
*/
-
public function stringifyArgs(array $args): string
-
{
-
$holder = [];
-
-
foreach ($args as $arg) {
-
$holder[] = $this->stringifyArg($arg);
-
}
-
-
return implode(', ', $holder);
-
}
-
-
/**
-
* Converts the provided argument into a string representation.
-
*
-
* @param mixed $arg The argument to be converted into a string. This can be of any type.
-
*
-
* @return string A string representation of the provided argument.
-
*/
-
protected function stringifyArg(mixed $arg): string
-
{
-
if (is_scalar($arg)) {
-
return var_export($arg, true);
-
}
-
-
if (is_object($arg)) {
-
return method_exists($arg, '__toString') ? (string) $arg : get_class($arg);
-
}
-
-
if (is_array($arg)) {
-
return '[' . $this->stringifyArgs($arg) . ']';
-
}
-
-
return gettype($arg);
-
}
-
-
/**
-
* @param Argument[] $arguments
-
* @param string $header
-
* @param string $footer
-
*
-
* @return self
-
*/
-
public function showArgumentsHelp(array $arguments, string $header = '', string $footer = ''): self
-
{
-
$this->showHelp('Arguments', $arguments, $header, $footer);
-
-
return $this;
-
}
-
-
/**
-
* @param Option[] $options
-
* @param string $header
-
* @param string $footer
-
*
-
* @return self
-
*/
-
public function showOptionsHelp(array $options, string $header = '', string $footer = ''): self
-
{
-
$this->showHelp('Options', $options, $header, $footer);
-
-
return $this;
-
}
-
-
/**
-
* @param Command[] $commands
-
* @param string $header
-
* @param string $footer
-
*
-
* @return self
-
*/
-
public function showCommandsHelp(array $commands, string $header = '', string $footer = ''): self
-
{
-
$this->maxCmdName = $commands ? max(array_map(static fn (Command $cmd) => strlen($cmd->name()), $commands)) : 0;
-
-
$this->showHelp('Commands', $commands, $header, $footer);
-
-
return $this;
-
}
-
-
/**
-
* Show help with headers and footers.
-
*/
-
protected function showHelp(string $for, array $items, string $header = '', string $footer = ''): void
-
{
-
if ($header) {
-
$this->writer->help_header($header, true);
-
}
-
-
$this->writer->eol()->help_category(t($for) . ':', true);
-
-
if (empty($items)) {
-
$this->writer->help_text(' (n/a)', true);
-
-
return;
-
}
-
-
$space = 4;
-
$lastGroup = null;
-
-
$withDefault = $for === 'Options' || $for === 'Arguments';
-
foreach (array_values($this->sortItems($items, $padLen, $for)) as $idx => $item) {
-
$name = $this->getName($item);
-
if ($for === 'Commands' && $lastGroup !== $group = $item->group()) {
-
$lastGroup = $group;
-
if ($group !== '') {
-
$this->writer->help_group($group, true);
-
}
-
}
-
$desc = str_replace(["\r\n", "\n"], str_pad("\n", $padLen + $space + 3), $item->desc($withDefault));
-
-
if ($idx % 2 == 0) {
-
$this->writer->help_item_even(' ' . str_pad($name, $padLen + $space));
-
$this->writer->help_description_even($desc, true);
-
} else {
-
$this->writer->help_item_odd(' ' . str_pad($name, $padLen + $space));
-
$this->writer->help_description_odd($desc, true);
-
}
-
}
-
-
if ($footer) {
-
$this->writer->eol()->help_footer($footer, true);
-
}
-
}
-
-
/**
-
* Show usage examples of a Command.
-
*
-
* It replaces $0 with actual command name and properly pads ` ## ` segments.
-
*/
-
public function showUsage(string $usage): self
-
{
-
$usage = str_replace('$0', $_SERVER['argv'][0] ?? '[cmd]', $usage);
-
-
if (!str_contains($usage, ' ## ')) {
-
$this->writer->eol()->help_category(t('Usage Examples') . ':', true)->colors($usage)->eol();
-
-
return $this;
-
}
-
-
$lines = explode("\n", str_replace(['<eol>', '<eol/>', '</eol>', "\r\n"], "\n", $usage));
-
foreach ($lines as $i => &$pos) {
-
if (false === $pos = strrpos(preg_replace('~</?\w+/?>~', '', $pos), ' ##')) {
-
unset($lines[$i]);
-
}
-
}
-
-
$maxlen = ($lines ? max($lines) : 0) + 4;
-
$usage = preg_replace_callback('~ ## ~', static function () use (&$lines, $maxlen) {
-
return str_pad('# ', $maxlen - array_shift($lines), ' ', STR_PAD_LEFT);
-
}, $usage);
-
-
$this->writer->eol()->help_category(t('Usage Examples') . ':', true)->colors($usage)->eol();
-
-
return $this;
-
}
-
-
/**
-
* Shows an error message when a command is not found and suggests similar commands.
-
* Uses levenshtein distance to find commands that are similar to the attempted one.
-
*
-
* @param string $attempted The command name that was attempted to be executed
-
* @param array $available List of available command names
-
*
-
* @return OutputHelper For method chaining
-
*/
-
public function showCommandNotFound(string $attempted, array $available): self
-
{
-
$closest = [];
-
foreach ($available as $cmd) {
-
$lev = levenshtein($attempted, $cmd);
-
if ($lev > 0 && $lev < 5) {
-
$closest[$cmd] = $lev;
-
}
-
}
-
-
$this->writer->error(t('Command %s not found', [$attempted]), true);
-
if ($closest) {
-
asort($closest);
-
$closest = key($closest);
-
$this->writer->bgRed(t('Did you mean %s?', [$closest]), true);
-
}
-
-
return $this;
-
}
-
-
/**
-
* Sort items by name. As a side effect sets max length of all names.
-
*
-
* @param Parameter[]|Command[] $items
-
* @param int|null $max
-
* @param string $for
-
*
-
* @return array
-
*/
-
protected function sortItems(array $items, ?int &$max = 0, string $for = ''): array
-
{
-
$max = max(array_map(fn ($item) => strlen($this->getName($item)), $items));
-
-
if ($for === 'Arguments') { // Arguments are positional so must not be sorted
-
return $items;
-
}
-
-
uasort($items, static function ($a, $b) {
-
// Items in the default group (where group() returns empty/falsy) are prefixed with '__'
-
// to ensure they appear at the top of the sorted list, whilst grouped items follow after
-
$aName = $a instanceof Groupable ? ($a->group() ?: '__') . $a->name() : $a->name();
-
$bName = $b instanceof Groupable ? ($b->group() ?: '__') . $b->name() : $b->name();
-
-
return $aName <=> $bName;
-
});
-
-
return $items;
-
}
-
-
/**
-
* Prepare name for different items.
-
*
-
* @param Parameter|Command $item
-
*
-
* @return string
-
*/
-
protected function getName(Parameter|Command $item): string
-
{
-
$name = $item->name();
-
-
if ($item instanceof Command) {
-
return trim(str_pad($name, $this->maxCmdName) . ' ' . $item->alias());
-
}
-
-
return $this->label($item);
-
}
-
-
/**
-
* Get parameter label for humans.
-
*/
-
protected function label(Parameter $item): string
-
{
-
$name = $item->name();
-
-
if ($item instanceof Option) {
-
$name = $item->short() . '|' . $item->long();
-
}
-
-
$variad = $item->variadic() ? '...' : '';
-
-
if ($item->required()) {
-
return "<$name$variad>";
-
}
-
-
return "[$name$variad]";
-
}
-
}
-333
vendor/adhocore/cli/src/Helper/Shell.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Helper;
-
-
use Ahc\Cli\Exception\RuntimeException;
-
-
use function Ahc\Cli\t;
-
use function fclose;
-
use function function_exists;
-
use function fwrite;
-
use function is_resource;
-
use function microtime;
-
use function proc_close;
-
use function proc_get_status;
-
use function proc_open;
-
use function proc_terminate;
-
use function stream_get_contents;
-
use function stream_set_blocking;
-
-
/**
-
* A thin proc_open wrapper to execute shell commands.
-
*
-
* With some inspirations from symfony/process.
-
*
-
* @author Sushil Gupta <desushil@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
class Shell
-
{
-
const STDIN_DESCRIPTOR_KEY = 0;
-
const STDOUT_DESCRIPTOR_KEY = 1;
-
const STDERR_DESCRIPTOR_KEY = 2;
-
-
const STATE_READY = 'ready';
-
const STATE_STARTED = 'started';
-
const STATE_CLOSED = 'closed';
-
const STATE_TERMINATED = 'terminated';
-
-
const DEFAULT_STDIN_WIN = ['pipe', 'r'];
-
const DEFAULT_STDIN_NIX = ['pipe', 'r'];
-
-
const DEFAULT_STDOUT_WIN = ['pipe', 'w'];
-
const DEFAULT_STDOUT_NIX = ['pipe', 'w'];
-
-
const DEFAULT_STDERR_WIN = ['pipe', 'w'];
-
const DEFAULT_STDERR_NIX = ['pipe', 'w'];
-
-
/** @var bool Whether to wait for the process to finish or return instantly */
-
protected bool $async = false;
-
-
/** @var string Current working directory */
-
protected ?string $cwd = null;
-
-
/** @var array Descriptor to be passed for proc_open */
-
protected array $descriptors;
-
-
/** @var array An array of environment variables */
-
protected ?array $env = null;
-
-
/** @var int Exit code of the process once it has been terminated */
-
protected ?int $exitCode = null;
-
-
/** @var array Other options to be passed for proc_open */
-
protected array $otherOptions = [];
-
-
/** @var array Pointers to stdin, stdout & stderr */
-
protected array $pipes = [];
-
-
/** @var resource The actual process resource returned from proc_open */
-
protected $process = null;
-
-
/** @var float Process starting time in unix timestamp */
-
protected float $processStartTime = 0;
-
-
/** @var array Status of the process as returned from proc_get_status */
-
protected ?array $processStatus = null;
-
-
/** @var float Default timeout for the process in seconds with microseconds */
-
protected ?float $processTimeout = null;
-
-
/** @var string Current state of the shell execution, set from this class, NOT for proc_get_status */
-
protected string $state = self::STATE_READY;
-
-
/**
-
* @param string $command Command to be executed
-
* @param string $input Input for stdin
-
*/
-
public function __construct(protected string $command, protected ?string $input = null)
-
{
-
// @codeCoverageIgnoreStart
-
if (!function_exists('proc_open')) {
-
throw new RuntimeException(t('Required proc_open could not be found in your PHP setup.'));
-
}
-
// @codeCoverageIgnoreEnd
-
-
$this->command = $command;
-
$this->input = $input;
-
}
-
-
protected function prepareDescriptors(?array $stdin = null, ?array $stdout = null, ?array $stderr = null): array
-
{
-
$win = Terminal::isWindows();
-
if (!$stdin) {
-
$stdin = $win ? self::DEFAULT_STDIN_WIN : self::DEFAULT_STDIN_NIX;
-
}
-
if (!$stdout) {
-
$stdout = $win ? self::DEFAULT_STDOUT_WIN : self::DEFAULT_STDOUT_NIX;
-
}
-
if (!$stderr) {
-
$stderr = $win ? self::DEFAULT_STDERR_WIN : self::DEFAULT_STDERR_NIX;
-
}
-
-
return [
-
self::STDIN_DESCRIPTOR_KEY => $stdin,
-
self::STDOUT_DESCRIPTOR_KEY => $stdout,
-
self::STDERR_DESCRIPTOR_KEY => $stderr,
-
];
-
}
-
-
protected function setInput(): void
-
{
-
//Make sure the pipe is a stream resource before writing to it to avoid a warning
-
if (is_resource($this->pipes[self::STDIN_DESCRIPTOR_KEY])) {
-
fwrite($this->pipes[self::STDIN_DESCRIPTOR_KEY], $this->input ?? '');
-
}
-
}
-
-
protected function updateProcessStatus(): void
-
{
-
if ($this->state === self::STATE_STARTED) {
-
$this->processStatus = proc_get_status($this->process);
-
-
if ($this->processStatus['running'] === false && $this->exitCode === null) {
-
$this->exitCode = $this->processStatus['exitcode'];
-
}
-
}
-
}
-
-
protected function closePipes(): void
-
{
-
//Make sure the pipe are a stream resource before closing them to avoid a warning
-
if (is_resource($this->pipes[self::STDIN_DESCRIPTOR_KEY])) {
-
fclose($this->pipes[self::STDIN_DESCRIPTOR_KEY]);
-
}
-
if (is_resource($this->pipes[self::STDOUT_DESCRIPTOR_KEY])) {
-
fclose($this->pipes[self::STDOUT_DESCRIPTOR_KEY]);
-
}
-
if (is_resource($this->pipes[self::STDERR_DESCRIPTOR_KEY])) {
-
fclose($this->pipes[self::STDERR_DESCRIPTOR_KEY]);
-
}
-
}
-
-
protected function wait(): ?int
-
{
-
while ($this->isRunning()) {
-
usleep(5000);
-
$this->checkTimeout();
-
}
-
-
return $this->exitCode;
-
}
-
-
protected function checkTimeout(): void
-
{
-
if ($this->processTimeout === null) {
-
return;
-
}
-
-
$executionDuration = microtime(true) - $this->processStartTime;
-
-
if ($executionDuration > $this->processTimeout) {
-
$this->kill();
-
-
throw new RuntimeException(t('Timeout occurred, process terminated.'));
-
}
-
// @codeCoverageIgnoreStart
-
}
-
// @codeCoverageIgnoreEnd
-
-
public function setOptions(
-
?string $cwd = null,
-
?array $env = null,
-
?float $timeout = null,
-
array $otherOptions = []
-
): self {
-
$this->cwd = $cwd;
-
$this->env = $env;
-
$this->processTimeout = $timeout;
-
$this->otherOptions = $otherOptions;
-
-
return $this;
-
}
-
-
/**
-
* execute
-
* Execute the command with optional stdin, stdout and stderr which override the defaults
-
* If async is set to true, the process will be executed in the background.
-
*
-
* @param bool $async - default false
-
* @param ?array $stdin - default null (loads default descriptor)
-
* @param ?array $stdout - default null (loads default descriptor)
-
* @param ?array $stderr - default null (loads default descriptor)
-
*
-
* @return self
-
*/
-
public function execute(bool $async = false, ?array $stdin = null, ?array $stdout = null, ?array $stderr = null): self
-
{
-
if ($this->isRunning()) {
-
throw new RuntimeException(t('Process is already running.'));
-
}
-
-
$this->descriptors = $this->prepareDescriptors($stdin, $stdout, $stderr);
-
$this->processStartTime = microtime(true);
-
-
$this->process = proc_open(
-
$this->command,
-
$this->descriptors,
-
$this->pipes,
-
$this->cwd,
-
$this->env,
-
$this->otherOptions
-
);
-
$this->setInput();
-
-
// @codeCoverageIgnoreStart
-
if (!is_resource($this->process)) {
-
throw new RuntimeException(t('Bad program could not be started.'));
-
}
-
// @codeCoverageIgnoreEnd
-
-
$this->state = self::STATE_STARTED;
-
-
$this->updateProcessStatus();
-
-
if ($this->async = $async) {
-
$this->setOutputStreamNonBlocking();
-
} else {
-
$this->wait();
-
}
-
-
return $this;
-
}
-
-
private function setOutputStreamNonBlocking(): bool
-
{
-
$isRes = is_resource($this->pipes[self::STDOUT_DESCRIPTOR_KEY]);
-
-
return $isRes ? stream_set_blocking($this->pipes[self::STDOUT_DESCRIPTOR_KEY], false) : false;
-
}
-
-
public function getState(): string
-
{
-
return $this->state;
-
}
-
-
public function getOutput(): string
-
{
-
$isRes = is_resource($this->pipes[self::STDOUT_DESCRIPTOR_KEY]);
-
-
return $isRes ? stream_get_contents($this->pipes[self::STDOUT_DESCRIPTOR_KEY]) : '';
-
}
-
-
public function getErrorOutput(): string
-
{
-
$isRes = is_resource($this->pipes[self::STDERR_DESCRIPTOR_KEY]);
-
-
return $isRes ? stream_get_contents($this->pipes[self::STDERR_DESCRIPTOR_KEY]) : '';
-
}
-
-
public function getExitCode(): ?int
-
{
-
$this->updateProcessStatus();
-
-
return $this->exitCode;
-
}
-
-
public function isRunning(): bool
-
{
-
if (self::STATE_STARTED !== $this->state) {
-
return false;
-
}
-
-
$this->updateProcessStatus();
-
-
return $this->processStatus['running'];
-
}
-
-
public function getProcessId(): ?int
-
{
-
return $this->isRunning() ? $this->processStatus['pid'] : null;
-
}
-
-
public function stop(): ?int
-
{
-
$this->closePipes();
-
-
if (is_resource($this->process)) {
-
proc_close($this->process);
-
}
-
-
$this->state = self::STATE_CLOSED;
-
-
$this->exitCode = $this->processStatus['exitcode'];
-
-
return $this->exitCode;
-
}
-
-
public function kill(): void
-
{
-
if (is_resource($this->process)) {
-
proc_terminate($this->process);
-
}
-
-
$this->state = self::STATE_TERMINATED;
-
}
-
-
public function __destruct()
-
{
-
// If async (run in background) => we don't care if it ever closes
-
// Otherwise, waited already till it ends itself or timeout occurs, in which case kill it
-
}
-
}
-99
vendor/adhocore/cli/src/Helper/Terminal.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Helper;
-
-
use function array_map;
-
use function array_search;
-
use function exec;
-
use function implode;
-
use function is_array;
-
use function preg_match_all;
-
-
/**
-
* A thin to find some information about the current terminal (width, height, ect...).
-
*
-
* @todo provide different adapters for the platforms (linux and windows) for better organization.
-
*
-
* @author Dimitri Sitchet Tomkeu <devcode.dst@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
class Terminal
-
{
-
public static function isWindows(): bool
-
{
-
// If PHP_OS is defined, use it - More reliable:
-
if (defined('PHP_OS')) {
-
return str_starts_with(strtoupper(PHP_OS), 'WIN'); // May be 'WINNT' or 'WIN32' or 'Windows'
-
}
-
-
// @codeCoverageIgnoreStart
-
return '\\' === DIRECTORY_SEPARATOR; // Fallback - Less reliable (Windows 7...)
-
// @codeCoverageIgnoreEnd
-
}
-
-
/**
-
* Get the width of the terminal.
-
*/
-
public function width(): ?int
-
{
-
return $this->getDimension('width');
-
}
-
-
/**
-
* Get the height of the terminal.
-
*/
-
public function height(): ?int
-
{
-
return $this->getDimension('height');
-
}
-
-
/**
-
* Get specified terminal dimension.
-
*/
-
protected function getDimension(string $key): ?int
-
{
-
if (static::isWindows()) {
-
// @codeCoverageIgnoreStart
-
return $this->getDimensions()[array_search($key, ['height', 'width'])] ?? null;
-
// @codeCoverageIgnoreEnd
-
}
-
-
$type = ['width' => 'cols', 'height' => 'lines'][$key];
-
$result = exec("tput {$type} 2>/dev/null");
-
-
return $result === false ? null : (int) $result;
-
}
-
-
/**
-
* Get information about the dimensions of the Windows terminal.
-
*
-
* @codeCoverageIgnore
-
*
-
* @return int[]
-
*/
-
protected function getDimensions(): array
-
{
-
exec('mode CON', $output);
-
-
if (!is_array($output)) {
-
return [];
-
}
-
-
$output = implode("\n", $output);
-
-
preg_match_all('/.*:\s*(\d+)/', $output, $matches);
-
-
return array_map('intval', $matches[1] ?? []);
-
}
-
}
-439
vendor/adhocore/cli/src/IO/Interactor.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\IO;
-
-
use Ahc\Cli\Input\Reader;
-
use Ahc\Cli\Output\Writer;
-
use Throwable;
-
-
use function Ahc\Cli\t;
-
use function array_keys;
-
use function array_map;
-
use function count;
-
use function explode;
-
use function func_get_args;
-
use function in_array;
-
use function is_string;
-
use function ltrim;
-
use function max;
-
use function method_exists;
-
use function range;
-
use function str_pad;
-
use function str_replace;
-
use function strtolower;
-
-
/**
-
* Cli Interactor.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*
-
* @method Writer answer($text, $eol = false)
-
* @method Writer bgBlack($text, $eol = false)
-
* @method Writer bgBlue($text, $eol = false)
-
* @method Writer bgCyan($text, $eol = false)
-
* @method Writer bgGreen($text, $eol = false)
-
* @method Writer bgPurple($text, $eol = false)
-
* @method Writer bgRed($text, $eol = false)
-
* @method Writer bgWhite($text, $eol = false)
-
* @method Writer bgYellow($text, $eol = false)
-
* @method Writer black($text, $eol = false)
-
* @method Writer blackBgBlue($text, $eol = false)
-
* @method Writer blackBgCyan($text, $eol = false)
-
* @method Writer blackBgGreen($text, $eol = false)
-
* @method Writer blackBgPurple($text, $eol = false)
-
* @method Writer blackBgRed($text, $eol = false)
-
* @method Writer blackBgWhite($text, $eol = false)
-
* @method Writer blackBgYellow($text, $eol = false)
-
* @method Writer blue($text, $eol = false)
-
* @method Writer blueBgBlack($text, $eol = false)
-
* @method Writer blueBgCyan($text, $eol = false)
-
* @method Writer blueBgGreen($text, $eol = false)
-
* @method Writer blueBgPurple($text, $eol = false)
-
* @method Writer blueBgRed($text, $eol = false)
-
* @method Writer blueBgWhite($text, $eol = false)
-
* @method Writer blueBgYellow($text, $eol = false)
-
* @method Writer bold($text, $eol = false)
-
* @method Writer boldBlack($text, $eol = false)
-
* @method Writer boldBlackBgBlue($text, $eol = false)
-
* @method Writer boldBlackBgCyan($text, $eol = false)
-
* @method Writer boldBlackBgGreen($text, $eol = false)
-
* @method Writer boldBlackBgPurple($text, $eol = false)
-
* @method Writer boldBlackBgRed($text, $eol = false)
-
* @method Writer boldBlackBgWhite($text, $eol = false)
-
* @method Writer boldBlackBgYellow($text, $eol = false)
-
* @method Writer boldBlue($text, $eol = false)
-
* @method Writer boldBlueBgBlack($text, $eol = false)
-
* @method Writer boldBlueBgCyan($text, $eol = false)
-
* @method Writer boldBlueBgGreen($text, $eol = false)
-
* @method Writer boldBlueBgPurple($text, $eol = false)
-
* @method Writer boldBlueBgRed($text, $eol = false)
-
* @method Writer boldBlueBgWhite($text, $eol = false)
-
* @method Writer boldBlueBgYellow($text, $eol = false)
-
* @method Writer boldCyan($text, $eol = false)
-
* @method Writer boldCyanBgBlack($text, $eol = false)
-
* @method Writer boldCyanBgBlue($text, $eol = false)
-
* @method Writer boldCyanBgGreen($text, $eol = false)
-
* @method Writer boldCyanBgPurple($text, $eol = false)
-
* @method Writer boldCyanBgRed($text, $eol = false)
-
* @method Writer boldCyanBgWhite($text, $eol = false)
-
* @method Writer boldCyanBgYellow($text, $eol = false)
-
* @method Writer boldGreen($text, $eol = false)
-
* @method Writer boldGreenBgBlack($text, $eol = false)
-
* @method Writer boldGreenBgBlue($text, $eol = false)
-
* @method Writer boldGreenBgCyan($text, $eol = false)
-
* @method Writer boldGreenBgPurple($text, $eol = false)
-
* @method Writer boldGreenBgRed($text, $eol = false)
-
* @method Writer boldGreenBgWhite($text, $eol = false)
-
* @method Writer boldGreenBgYellow($text, $eol = false)
-
* @method Writer boldPurple($text, $eol = false)
-
* @method Writer boldPurpleBgBlack($text, $eol = false)
-
* @method Writer boldPurpleBgBlue($text, $eol = false)
-
* @method Writer boldPurpleBgCyan($text, $eol = false)
-
* @method Writer boldPurpleBgGreen($text, $eol = false)
-
* @method Writer boldPurpleBgRed($text, $eol = false)
-
* @method Writer boldPurpleBgWhite($text, $eol = false)
-
* @method Writer boldPurpleBgYellow($text, $eol = false)
-
* @method Writer boldRed($text, $eol = false)
-
* @method Writer boldRedBgBlack($text, $eol = false)
-
* @method Writer boldRedBgBlue($text, $eol = false)
-
* @method Writer boldRedBgCyan($text, $eol = false)
-
* @method Writer boldRedBgGreen($text, $eol = false)
-
* @method Writer boldRedBgPurple($text, $eol = false)
-
* @method Writer boldRedBgWhite($text, $eol = false)
-
* @method Writer boldRedBgYellow($text, $eol = false)
-
* @method Writer boldWhite($text, $eol = false)
-
* @method Writer boldWhiteBgBlack($text, $eol = false)
-
* @method Writer boldWhiteBgBlue($text, $eol = false)
-
* @method Writer boldWhiteBgCyan($text, $eol = false)
-
* @method Writer boldWhiteBgGreen($text, $eol = false)
-
* @method Writer boldWhiteBgPurple($text, $eol = false)
-
* @method Writer boldWhiteBgRed($text, $eol = false)
-
* @method Writer boldWhiteBgYellow($text, $eol = false)
-
* @method Writer boldYellow($text, $eol = false)
-
* @method Writer boldYellowBgBlack($text, $eol = false)
-
* @method Writer boldYellowBgBlue($text, $eol = false)
-
* @method Writer boldYellowBgCyan($text, $eol = false)
-
* @method Writer boldYellowBgGreen($text, $eol = false)
-
* @method Writer boldYellowBgPurple($text, $eol = false)
-
* @method Writer boldYellowBgRed($text, $eol = false)
-
* @method Writer boldYellowBgWhite($text, $eol = false)
-
* @method Writer choice($text, $eol = false)
-
* @method Writer colors($text)
-
* @method Writer comment($text, $eol = false)
-
* @method Writer cyan($text, $eol = false)
-
* @method Writer cyanBgBlack($text, $eol = false)
-
* @method Writer cyanBgBlue($text, $eol = false)
-
* @method Writer cyanBgGreen($text, $eol = false)
-
* @method Writer cyanBgPurple($text, $eol = false)
-
* @method Writer cyanBgRed($text, $eol = false)
-
* @method Writer cyanBgWhite($text, $eol = false)
-
* @method Writer cyanBgYellow($text, $eol = false)
-
* @method Writer eol(int $n = 1)
-
* @method Writer error($text, $eol = false)
-
* @method Writer green($text, $eol = false)
-
* @method Writer greenBgBlack($text, $eol = false)
-
* @method Writer greenBgBlue($text, $eol = false)
-
* @method Writer greenBgCyan($text, $eol = false)
-
* @method Writer greenBgPurple($text, $eol = false)
-
* @method Writer greenBgRed($text, $eol = false)
-
* @method Writer greenBgWhite($text, $eol = false)
-
* @method Writer greenBgYellow($text, $eol = false)
-
* @method Writer help_category($text, $eol = false)
-
* @method Writer help_description_even($text, $eol = false)
-
* @method Writer help_description_odd($text, $eol = false)
-
* @method Writer help_example($text, $eol = false)
-
* @method Writer help_footer($text, $eol = false)
-
* @method Writer help_group($text, $eol = false)
-
* @method Writer help_header($text, $eol = false)
-
* @method Writer help_item_even($text, $eol = false)
-
* @method Writer help_item_odd($text, $eol = false)
-
* @method Writer help_summary($text, $eol = false)
-
* @method Writer help_text($text, $eol = false)
-
* @method Writer info($text, $eol = false)
-
* @method Writer logo($text, $eol = false)
-
* @method Writer ok($text, $eol = false)
-
* @method Writer purple($text, $eol = false)
-
* @method Writer purpleBgBlack($text, $eol = false)
-
* @method Writer purpleBgBlue($text, $eol = false)
-
* @method Writer purpleBgCyan($text, $eol = false)
-
* @method Writer purpleBgGreen($text, $eol = false)
-
* @method Writer purpleBgRed($text, $eol = false)
-
* @method Writer purpleBgWhite($text, $eol = false)
-
* @method Writer purpleBgYellow($text, $eol = false)
-
* @method Writer question($text, $eol = false)
-
* @method Writer red($text, $eol = false)
-
* @method Writer redBgBlack($text, $eol = false)
-
* @method Writer redBgBlue($text, $eol = false)
-
* @method Writer redBgCyan($text, $eol = false)
-
* @method Writer redBgGreen($text, $eol = false)
-
* @method Writer redBgPurple($text, $eol = false)
-
* @method Writer redBgWhite($text, $eol = false)
-
* @method Writer redBgYellow($text, $eol = false)
-
* @method Writer table(array $rows, array $styles = [])
-
* @method Writer version($text, $eol = false)
-
* @method Writer warn($text, $eol = false)
-
* @method Writer white($text, $eol = false)
-
* @method Writer yellow($text, $eol = false)
-
* @method Writer yellowBgBlack($text, $eol = false)
-
* @method Writer yellowBgBlue($text, $eol = false)
-
* @method Writer yellowBgCyan($text, $eol = false)
-
* @method Writer yellowBgGreen($text, $eol = false)
-
* @method Writer yellowBgPurple($text, $eol = false)
-
* @method Writer yellowBgRed($text, $eol = false)
-
* @method Writer yellowBgWhite($text, $eol = false)
-
*/
-
class Interactor
-
{
-
protected Reader $reader;
-
protected Writer $writer;
-
-
/**
-
* Constructor.
-
*
-
* @param string|null $input Input stream path.
-
* @param string|null $output Output steam path.
-
*/
-
public function __construct(?string $input = null, ?string $output = null)
-
{
-
$this->reader = new Reader($input);
-
$this->writer = new Writer($output);
-
}
-
-
/**
-
* Get reader.
-
*
-
* @return Reader
-
*/
-
public function reader(): Reader
-
{
-
return $this->reader;
-
}
-
-
/**
-
* Get writer.
-
*
-
* @return Writer
-
*/
-
public function writer(): Writer
-
{
-
return $this->writer;
-
}
-
-
/**
-
* Confirms if user agrees to prompt as indicated by given text.
-
*
-
* @param string $text Eg: `Are you sure?`
-
* @param string $default One of `y|n`
-
*
-
* @return bool
-
*/
-
public function confirm(string $text, string $default = 'y'): bool
-
{
-
$choice = $this->choice($text, ['y', 'n'], $default, false);
-
-
return strtolower($choice[0] ?? $default) === 'y';
-
}
-
-
/**
-
* Let user make a choice out of available choices.
-
*
-
* @param string $text Prompt text.
-
* @param array $choices Possible choices for user.
-
* @param mixed $default Default value- if not chosen or invalid.
-
* @param bool $case If user input should be case sensitive.
-
*
-
* @return mixed User input or default.
-
*/
-
public function choice(string $text, array $choices, $default = null, bool $case = false): mixed
-
{
-
$this->writer->question($text);
-
-
$this->listOptions($choices, $default, false);
-
-
$choice = $this->reader->read($default);
-
-
return $this->isValidChoice($choice, $choices, $case) ? $choice : $default;
-
}
-
-
/**
-
* Let user make multiple choices out of available choices.
-
*
-
* @param string $text Prompt text.
-
* @param array $choices Possible choices for user.
-
* @param mixed $default Default value- if not chosen or invalid.
-
* @param bool $case If user input should be case sensitive.
-
*
-
* @return mixed User input or default.
-
*/
-
public function choices(string $text, array $choices, $default = null, bool $case = false): mixed
-
{
-
$this->writer->question($text);
-
-
$this->listOptions($choices, $default, true);
-
-
$choice = $this->reader->read($default);
-
-
if (is_string($choice)) {
-
$choice = explode(',', str_replace(' ', '', $choice));
-
}
-
-
$valid = [];
-
-
foreach ($choice as $option) {
-
if ($this->isValidChoice($option, $choices, $case)) {
-
$valid[] = $option;
-
}
-
}
-
-
return $valid ?: (array) $default;
-
}
-
-
/**
-
* Prompt user for free input.
-
*
-
* @param string $text Prompt text.
-
* @param mixed $default
-
* @param callable|null $fn The sanitizer/validator for user input
-
* Any exception message is printed and prompted again.
-
* @param int $retry How many more times to retry on failure.
-
*
-
* @return mixed
-
*/
-
public function prompt(string $text, $default = null, ?callable $fn = null, int $retry = 3): mixed
-
{
-
$error = t('Invalid value. Please try again!');
-
$hidden = func_get_args()[4] ?? false;
-
$readFn = ['read', 'readHidden'][(int) $hidden];
-
-
$this->writer->question($text)->answer(null !== $default ? " [$default]: " : ': ');
-
-
try {
-
$input = $this->reader->{$readFn}($default, $fn);
-
} catch (Throwable $e) {
-
$input = '';
-
$error = $e->getMessage();
-
}
-
-
if ($retry > 0 && $input === '') {
-
$this->writer->error($error, true);
-
-
return $this->prompt($text, $default, $fn, $retry - 1, $hidden);
-
}
-
-
return $input ?? $default;
-
}
-
-
/**
-
* Prompt user for secret input like password. Currently for unix only.
-
*
-
* @param string $text Prompt text.
-
* @param callable|null $fn The sanitizer/validator for user input
-
* Any exception message is printed as error.
-
* @param int $retry How many more times to retry on failure.
-
*
-
* @return mixed
-
*/
-
public function promptHidden(string $text, ?callable $fn = null, int $retry = 3): mixed
-
{
-
return $this->prompt($text, null, $fn, $retry, true);
-
}
-
-
/**
-
* Show choices list.
-
*
-
* @param array $choices Available choices.
-
* @param mixed $default
-
* @param bool $multi Indicates multiple choices.
-
*
-
* @return self
-
*/
-
protected function listOptions(array $choices, $default = null, bool $multi = false): self
-
{
-
if (!$this->isAssocChoice($choices)) {
-
return $this->promptOptions($choices, $default);
-
}
-
-
$maxLen = max(array_map('strlen', array_keys($choices)));
-
-
foreach ($choices as $choice => $desc) {
-
$this->writer->eol()->choice(str_pad(" [$choice]", $maxLen + 6))->answer($desc);
-
}
-
-
$label = t($multi ? 'Choices (comma separated)' : 'Choice');
-
-
$this->writer->eol()->question($label);
-
-
return $this->promptOptions(array_keys($choices), $default);
-
}
-
-
/**
-
* Show prompt with possible options.
-
*/
-
protected function promptOptions(array $choices, mixed $default): self
-
{
-
$options = '';
-
-
foreach ($choices as $choice) {
-
$style = in_array($choice, (array) $default) ? 'boldChoice' : 'choice';
-
$options .= "/<$style>$choice</end>";
-
}
-
-
$options = ltrim($options, '/');
-
-
$this->writer->colors(" ($options): ");
-
-
return $this;
-
}
-
-
/**
-
* Check if user choice is one of possible choices.
-
*/
-
protected function isValidChoice(string $choice, array $choices, bool $case): bool
-
{
-
if ($this->isAssocChoice($choices)) {
-
$choices = array_keys($choices);
-
}
-
-
$fn = ['\strcasecmp', '\strcmp'][(int) $case];
-
-
foreach ($choices as $option) {
-
if ($fn($choice, $option) == 0) {
-
return true;
-
}
-
}
-
-
return false;
-
}
-
-
/**
-
* Check if the choices array is associative.
-
*/
-
protected function isAssocChoice(array $array): bool
-
{
-
return !empty($array) && array_keys($array) != range(0, count($array) - 1);
-
}
-
-
/**
-
* Channel method calls to reader/writer.
-
*/
-
public function __call(string $method, array $arguments)
-
{
-
if (method_exists($this->reader, $method)) {
-
return $this->reader->{$method}(...$arguments);
-
}
-
-
return $this->writer->{$method}(...$arguments);
-
}
-
}
-51
vendor/adhocore/cli/src/Input/Argument.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Input;
-
-
use function explode;
-
use function is_array;
-
use function str_replace;
-
use function strpos;
-
-
/**
-
* Cli Option.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
class Argument extends Parameter
-
{
-
/**
-
* {@inheritdoc}
-
*/
-
protected function parse(string $arg): void
-
{
-
$this->name = $name = str_replace(['<', '>', '[', ']', '.'], '', $arg);
-
-
// Format is "name:default+value1,default+value2" ('+' => ' ')!
-
if (strpos($name, ':') !== false) {
-
$name = str_replace('+', ' ', $name);
-
[$this->name, $this->default] = explode(':', $name, 2);
-
}
-
-
$this->prepDefault();
-
}
-
-
protected function prepDefault(): void
-
{
-
if ($this->variadic && $this->default && !is_array($this->default)) {
-
$this->default = explode(',', $this->default, 2);
-
}
-
}
-
}
-453
vendor/adhocore/cli/src/Input/Command.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Input;
-
-
use Ahc\Cli\Application as App;
-
use Ahc\Cli\Exception\InvalidParameterException;
-
use Ahc\Cli\Exception\RuntimeException;
-
use Ahc\Cli\Helper\InflectsString;
-
use Ahc\Cli\Helper\OutputHelper;
-
use Ahc\Cli\IO\Interactor;
-
use Ahc\Cli\Output\ProgressBar;
-
use Ahc\Cli\Output\Writer;
-
use Closure;
-
-
use function Ahc\Cli\t;
-
use function array_filter;
-
use function array_keys;
-
use function end;
-
use function explode;
-
use function func_num_args;
-
use function str_contains;
-
use function strstr;
-
-
/**
-
* Parser aware Command for the cli (based on tj/commander.js).
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
class Command extends Parser implements Groupable
-
{
-
use InflectsString;
-
-
protected $_action = null;
-
-
protected string $_group;
-
-
protected string $_version = '';
-
-
protected string $_usage = '';
-
-
protected ?string $_alias = null;
-
-
protected string $_logo = '';
-
-
protected string $_help = '';
-
-
private array $_events = [];
-
-
private bool $_argVariadic = false;
-
-
/**
-
* Constructor.
-
*
-
* @param string $name
-
* @param string $desc
-
* @param bool $allowUnknown
-
* @param App $app
-
*/
-
public function __construct(
-
protected string $_name,
-
protected string $_desc = '',
-
protected bool $_allowUnknown = false,
-
protected ?App $_app = null
-
) {
-
$this->defaults();
-
$this->inGroup(str_contains($_name, ':') ? strstr($_name, ':', true) : '');
-
}
-
-
/**
-
* Sets default options, actions and exit handler.
-
*/
-
protected function defaults(): self
-
{
-
$this->option('-h, --help', t('Show help'))->on([$this, 'showHelp']);
-
$this->option('-V, --version', t('Show version'))->on([$this, 'showVersion']);
-
$this->option('-v, --verbosity', t('Verbosity level'), null, 0)->on(
-
fn () => $this->set('verbosity', ($this->verbosity ?? 0) + 1) && false
-
);
-
-
$this->onExit(static fn ($exitCode = 0) => exit($exitCode));
-
-
return $this;
-
}
-
-
/**
-
* Sets version.
-
*/
-
public function version(string $version): self
-
{
-
$this->_version = $version;
-
-
return $this;
-
}
-
-
/**
-
* Gets command name.
-
*/
-
public function name(): string
-
{
-
return $this->_name;
-
}
-
-
/**
-
* Gets command description.
-
*/
-
public function desc(): string
-
{
-
return $this->_desc;
-
}
-
-
/**
-
* Sets command group.
-
*/
-
public function inGroup(string $group): self
-
{
-
$this->_group = $group;
-
-
return $this;
-
}
-
-
/**
-
* Gets command group.
-
*/
-
public function group(): string
-
{
-
return $this->_group;
-
}
-
-
/**
-
* Get the app this command belongs to.
-
*/
-
public function app(): ?App
-
{
-
return $this->_app;
-
}
-
-
/**
-
* Bind command to the app.
-
*/
-
public function bind(?App $app = null): self
-
{
-
$this->_app = $app;
-
-
return $this;
-
}
-
-
/**
-
* Sets or gets the ASCII art logo.
-
*
-
* @param string|null $logo
-
*
-
* @return string|self
-
*/
-
public function logo(?string $logo = null)
-
{
-
if (func_num_args() === 0) {
-
return $this->_logo;
-
}
-
-
$this->_logo = $logo;
-
-
return $this;
-
}
-
-
/**
-
* Registers argument definitions (all at once). Only last one can be variadic.
-
*/
-
public function arguments(string $definitions): self
-
{
-
$definitions = explode(' ', $definitions);
-
-
foreach ($definitions as $raw) {
-
$this->argument($raw);
-
}
-
-
return $this;
-
}
-
-
/**
-
* Register an argument.
-
*/
-
public function argument(string $raw, string $desc = '', $default = null): self
-
{
-
$argument = new Argument($raw, $desc, $default);
-
-
if ($this->_argVariadic) {
-
throw new InvalidParameterException(t('Only last argument can be variadic'));
-
}
-
-
if ($argument->variadic()) {
-
$this->_argVariadic = true;
-
}
-
-
$this->register($argument);
-
-
return $this;
-
}
-
-
/**
-
* Registers new option.
-
*/
-
public function option(string $raw, string $desc = '', ?callable $filter = null, $default = null): self
-
{
-
$option = new Option($raw, $desc, $default, $filter);
-
-
$this->register($option);
-
-
return $this;
-
}
-
-
/**
-
* Gets user options (i.e without defaults).
-
*/
-
public function userOptions(): array
-
{
-
$options = $this->allOptions();
-
-
unset($options['help'], $options['version'], $options['verbosity']);
-
-
return $options;
-
}
-
-
/**
-
* Gets or sets usage info.
-
*
-
* @param string|null $usage
-
*
-
* @return string|self
-
*/
-
public function usage(?string $usage = null)
-
{
-
if (func_num_args() === 0) {
-
return $this->_usage;
-
}
-
-
$this->_usage = $usage;
-
-
return $this;
-
}
-
-
/**
-
* Gets or sets alias.
-
*
-
* @param string|null $alias
-
*
-
* @return string|self
-
*/
-
public function alias(?string $alias = null)
-
{
-
if (func_num_args() === 0) {
-
return $this->_alias;
-
}
-
-
$this->_alias = $alias;
-
-
return $this;
-
}
-
-
/**
-
* Sets event handler for last (or given) option.
-
*/
-
public function on(callable $fn, ?string $option = null): self
-
{
-
$names = array_keys($this->allOptions());
-
-
$this->_events[$option ?? end($names)] = $fn;
-
-
return $this;
-
}
-
-
/**
-
* Register exit handler.
-
*/
-
public function onExit(callable $fn): self
-
{
-
$this->_events['_exit'] = $fn;
-
-
return $this;
-
}
-
-
/**
-
* {@inheritdoc}
-
*/
-
protected function handleUnknown(string $arg, ?string $value = null): mixed
-
{
-
if ($this->_allowUnknown) {
-
return $this->set($this->toCamelCase($arg), $value);
-
}
-
-
$values = array_filter($this->values(false));
-
-
// Has some value, error!
-
if ($values) {
-
throw new RuntimeException(t('Option "%s" not registered', [$arg]));
-
}
-
-
// Has no value, show help!
-
return $this->showHelp();
-
}
-
-
/**
-
* Sets or gets the custom help screen contents.
-
*
-
* @param string|null $help
-
*
-
* @return string|self
-
*/
-
public function help(?string $help = null): mixed
-
{
-
if (func_num_args() === 0) {
-
return $this->_help;
-
}
-
-
$this->_help = $help;
-
-
return $this;
-
}
-
-
/**
-
* Show custom help screen if one is set, otherwise shows the default one.
-
*/
-
public function showHelp(): mixed
-
{
-
if ($help = $this->help()) {
-
$writer = $this->io()->writer();
-
$writer->write($help, true);
-
-
return $this->emit('_exit', 0);
-
}
-
-
return $this->showDefaultHelp();
-
}
-
-
/**
-
* Shows command help then aborts.
-
*/
-
public function showDefaultHelp(): mixed
-
{
-
$io = $this->io();
-
$helper = new OutputHelper($io->writer());
-
$app = $this->app();
-
-
if (($logo = $this->logo()) || ($app && ($logo = $app->logo()) && $app->getDefaultCommand() === $this->_name)) {
-
$io->logo($logo, true);
-
}
-
-
$io->help_header(t('Command') . " {$this->_name}, " . t('version') . " {$this->_version}", true)->eol();
-
$io->help_summary($this->_desc, true)->eol();
-
$io->help_text(t('Usage') . ': ')->help_example("{$this->_name} " . t('[OPTIONS...] [ARGUMENTS...]'), true);
-
-
$helper
-
->showArgumentsHelp($this->allArguments())
-
->showOptionsHelp($this->allOptions(), '', t('Legend: <required> [optional] variadic...'));
-
-
if ($this->_usage) {
-
$helper->showUsage($this->_usage);
-
}
-
-
return $this->emit('_exit', 0);
-
}
-
-
/**
-
* Shows command version then aborts.
-
*/
-
public function showVersion(): mixed
-
{
-
$this->writer()->version($this->_version, true);
-
-
return $this->emit('_exit', 0);
-
}
-
-
/**
-
* {@inheritdoc}
-
*/
-
public function emit(string $event, $value = null): mixed
-
{
-
if (empty($this->_events[$event])) {
-
return null;
-
}
-
-
return ($this->_events[$event])($value);
-
}
-
-
/**
-
* Tap return given object or if that is null then app instance. This aids for chaining.
-
*/
-
public function tap(?object $object = null)
-
{
-
return $object ?? $this->_app;
-
}
-
-
/**
-
* Performs user interaction if required to set some missing values.
-
*/
-
public function interact(Interactor $io): void
-
{
-
// Subclasses will do the needful.
-
}
-
-
/**
-
* Get or set command action.
-
*
-
* @param callable|null $action If provided it is set
-
*
-
* @return callable|self If $action provided then self, otherwise the preset action.
-
*/
-
public function action(?callable $action = null)
-
{
-
if (func_num_args() === 0) {
-
return $this->_action;
-
}
-
-
$this->_action = $action instanceof Closure ? Closure::bind($action, $this) : $action;
-
-
return $this;
-
}
-
-
/**
-
* Get a writer instance.
-
*/
-
protected function writer(): Writer
-
{
-
return $this->_app ? $this->_app->io()->writer() : new Writer;
-
}
-
-
/**
-
* Get IO instance.
-
*/
-
protected function io(): Interactor
-
{
-
return $this->_app ? $this->_app->io() : new Interactor;
-
}
-
-
/**
-
* Get ProgressBar instance.
-
*/
-
protected function progress(?int $total = null): ProgressBar
-
{
-
return new ProgressBar($total, $this->writer());
-
}
-
}
-33
vendor/adhocore/cli/src/Input/Groupable.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Input;
-
-
/**
-
* Groupable.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
interface Groupable
-
{
-
/**
-
* Sets the group.
-
*/
-
public function inGroup(string $group): self;
-
-
/**
-
* Gets the group.
-
*/
-
public function group(): string;
-
}
-85
vendor/adhocore/cli/src/Input/Option.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Input;
-
-
use function preg_match;
-
use function preg_split;
-
use function str_replace;
-
use function strpos;
-
-
/**
-
* Cli Option.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
class Option extends Parameter
-
{
-
protected string $short = '';
-
-
protected string $long = '';
-
-
/**
-
* {@inheritdoc}
-
*/
-
protected function parse(string $raw): void
-
{
-
if (strpos($raw, '-with-') !== false) {
-
$this->default = false;
-
} elseif (strpos($raw, '-no-') !== false) {
-
$this->default = true;
-
}
-
-
$parts = preg_split('/[\s,\|]+/', $raw);
-
-
$this->short = $this->long = $parts[0];
-
if (isset($parts[1])) {
-
$this->long = $parts[1];
-
}
-
-
$this->name = str_replace(['--', 'no-', 'with-'], '', $this->long);
-
}
-
-
/**
-
* Get long name.
-
*/
-
public function long(): string
-
{
-
return $this->long;
-
}
-
-
/**
-
* Get short name.
-
*/
-
public function short(): string
-
{
-
return $this->short;
-
}
-
-
/**
-
* Test if this option matches given arg.
-
*/
-
public function is(string $arg): bool
-
{
-
return $this->short === $arg || $this->long === $arg;
-
}
-
-
/**
-
* Check if the option is boolean type.
-
*/
-
public function bool(): bool
-
{
-
return preg_match('/\-no-|\-with-/', $this->long) > 0;
-
}
-
}
-147
vendor/adhocore/cli/src/Input/Parameter.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Input;
-
-
use Ahc\Cli\Helper\InflectsString;
-
-
use function Ahc\Cli\t;
-
use function json_encode;
-
use function ltrim;
-
use function strpos;
-
-
/**
-
* Cli Parameter.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
abstract class Parameter
-
{
-
use InflectsString;
-
-
protected string $name;
-
-
protected bool $required = false;
-
-
protected bool $optional = false;
-
-
protected bool $variadic = false;
-
-
protected $filter = null;
-
-
public function __construct(
-
protected string $raw,
-
protected string $desc = '',
-
protected $default = null,
-
$filter = null
-
) {
-
$this->filter = $filter;
-
$this->required = strpos($raw, '<') !== false;
-
$this->optional = strpos($raw, '[') !== false;
-
$this->variadic = strpos($raw, '...') !== false;
-
-
$this->parse($raw);
-
}
-
-
/**
-
* Parse raw string representation of parameter.
-
*/
-
abstract protected function parse(string $raw): void;
-
-
/**
-
* Get raw definition.
-
*/
-
public function raw(): string
-
{
-
return $this->raw;
-
}
-
-
/**
-
* Get name.
-
*/
-
public function name(): string
-
{
-
return $this->name;
-
}
-
-
/**
-
* Get description.
-
*/
-
public function desc(bool $withDefault = false): string
-
{
-
if (!$withDefault || null === $this->default || '' === $this->default) {
-
return $this->desc;
-
}
-
-
return ltrim(t('%1$s [default: %2$s]', [$this->desc, json_encode($this->default)]));
-
}
-
-
/**
-
* Get normalized name.
-
*/
-
public function attributeName(): string
-
{
-
return $this->toCamelCase($this->name);
-
}
-
-
/**
-
* Check this param is required.
-
*/
-
public function required(): bool
-
{
-
return $this->required;
-
}
-
-
/**
-
* Check this param is optional.
-
*/
-
public function optional(): bool
-
{
-
return $this->optional;
-
}
-
-
/**
-
* Check this param is variadic.
-
*/
-
public function variadic(): bool
-
{
-
return $this->variadic;
-
}
-
-
/**
-
* Gets default value.
-
*/
-
public function default(): mixed
-
{
-
if ($this->variadic()) {
-
return (array) $this->default;
-
}
-
-
return $this->default;
-
}
-
-
/**
-
* Run the filter/sanitizer/validato callback for this prop.
-
*/
-
public function filter(mixed $raw): mixed
-
{
-
if ($this->filter) {
-
$callback = $this->filter;
-
-
return $callback($raw);
-
}
-
-
return $raw;
-
}
-
}
-330
vendor/adhocore/cli/src/Input/Parser.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Input;
-
-
use Ahc\Cli\Exception\InvalidParameterException;
-
use Ahc\Cli\Exception\RuntimeException;
-
use Ahc\Cli\Helper\Normalizer;
-
use InvalidArgumentException;
-
-
use function Ahc\Cli\t;
-
use function array_diff_key;
-
use function array_filter;
-
use function array_key_exists;
-
use function array_merge;
-
use function array_shift;
-
use function count;
-
use function in_array;
-
use function reset;
-
use function substr;
-
-
/**
-
* Argv parser for the cli.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
abstract class Parser
-
{
-
/** @var string|null The last seen variadic option name */
-
protected ?string $_lastVariadic = null;
-
-
protected Normalizer $_normalizer;
-
-
private array $_options = [];
-
-
private array $_arguments = [];
-
-
/** @var array Parsed values indexed by option name */
-
private array $_values = [];
-
-
/**
-
* Parse the argv input.
-
*
-
* @param array $argv The first item is ignored.
-
*
-
* @throws \RuntimeException When argument is missing or invalid.
-
*
-
* @return self
-
*/
-
public function parse(array $argv): self
-
{
-
$this->_normalizer = new Normalizer;
-
-
array_shift($argv);
-
-
$argv = $this->_normalizer->normalizeArgs($argv);
-
$count = count($argv);
-
$literal = false;
-
-
for ($i = 0; $i < $count; $i++) {
-
[$arg, $nextArg] = [$argv[$i], $argv[$i + 1] ?? null];
-
-
if ($arg === '--') {
-
$literal = true;
-
} elseif ($arg[0] !== '-' || $literal) {
-
$this->parseArgs($arg);
-
} else {
-
$i += (int) $this->parseOptions($arg, $nextArg);
-
}
-
}
-
-
$this->validate();
-
-
return $this;
-
}
-
-
/**
-
* Parse single arg.
-
*
-
* @param string $arg
-
*
-
* @return mixed
-
*/
-
protected function parseArgs(string $arg)
-
{
-
if ($this->_lastVariadic) {
-
return $this->set($this->_lastVariadic, $arg, true);
-
}
-
-
if (!$argument = reset($this->_arguments)) {
-
return $this->set(null, $arg);
-
}
-
-
$this->setValue($argument, $arg);
-
-
// Otherwise we will always collect same arguments again!
-
if (!$argument->variadic()) {
-
array_shift($this->_arguments);
-
}
-
}
-
-
/**
-
* Parse an option, emit its event and set value.
-
*
-
* @param string $arg
-
* @param string|null $nextArg
-
*
-
* @return bool Whether to eat next arg.
-
*/
-
protected function parseOptions(string $arg, ?string $nextArg = null): bool
-
{
-
$value = substr($nextArg ?? '', 0, 1) === '-' ? null : $nextArg;
-
-
if (null === $option = $this->optionFor($arg)) {
-
return $this->handleUnknown($arg, $value);
-
}
-
-
$this->_lastVariadic = $option->variadic() ? $option->attributeName() : null;
-
-
return false === $this->emit($option->attributeName(), $value) ? false : $this->setValue($option, $value);
-
}
-
-
/**
-
* Get matching option by arg (name) or null.
-
*/
-
protected function optionFor(string $arg): ?Option
-
{
-
foreach ($this->_options as $option) {
-
if ($option->is($arg)) {
-
return $option;
-
}
-
}
-
-
return null;
-
}
-
-
/**
-
* Handle Unknown option.
-
*
-
* @param string $arg Option name
-
* @param string|null $value Value
-
*
-
* @throws \RuntimeException When given arg is not registered and allow unkown flag is not set.
-
*
-
* @return mixed If true it will indicate that value has been eaten.
-
*/
-
abstract protected function handleUnknown(string $arg, ?string $value = null): mixed;
-
-
/**
-
* Emit the event with value.
-
*
-
* @param string $event Event name (is option name technically)
-
* @param mixed $value Value (is option value technically)
-
*
-
* @return mixed
-
*/
-
abstract protected function emit(string $event, $value = null): mixed;
-
-
/**
-
* Sets value of an option.
-
*
-
* @param Parameter $parameter
-
* @param string|null $value
-
*
-
* @return bool Indicating whether it has eaten adjoining arg to its right.
-
*/
-
protected function setValue(Parameter $parameter, ?string $value = null): bool
-
{
-
$name = $parameter->attributeName();
-
$value = $this->_normalizer->normalizeValue($parameter, $value);
-
-
return $this->set($name, $value, $parameter->variadic());
-
}
-
-
/**
-
* Set a raw value.
-
*/
-
protected function set($key, $value, bool $variadic = false): bool
-
{
-
if (null === $key) {
-
$this->_values[] = $value;
-
} elseif ($variadic) {
-
$this->_values[$key] = array_merge($this->_values[$key], (array) $value);
-
} else {
-
$this->_values[$key] = $value;
-
}
-
-
return !in_array($value, [true, false, null], true);
-
}
-
-
/**
-
* Validate if all required arguments/options have proper values.
-
*
-
* @throws RuntimeException If value missing for required ones.
-
*
-
* @return void
-
*/
-
protected function validate(): void
-
{
-
/** @var Parameter[] $missingItems */
-
/** @var Parameter $item */
-
$missingItems = array_filter(
-
$this->_options + $this->_arguments,
-
fn ($item) => $item->required() && in_array($this->_values[$item->attributeName()], [null, []])
-
);
-
-
foreach ($missingItems as $item) {
-
[$name, $label] = [$item->name(), 'Argument'];
-
if ($item instanceof Option) {
-
[$name, $label] = [$item->long(), 'Option'];
-
}
-
-
throw new RuntimeException(t('%1$s "%2$s" is required', [$label, $name]));
-
}
-
}
-
-
/**
-
* Register a new argument/option.
-
*/
-
protected function register(Parameter $param): void
-
{
-
$this->ifAlreadyRegistered($param);
-
-
$name = $param->attributeName();
-
if ($param instanceof Option) {
-
$this->_options[$name] = $param;
-
} else {
-
$this->_arguments[$name] = $param;
-
}
-
-
$this->set($name, $param->default());
-
}
-
-
/**
-
* Unset a registered argument/option.
-
*/
-
public function unset(string $name): self
-
{
-
unset($this->_values[$name], $this->_arguments[$name], $this->_options[$name]);
-
-
return $this;
-
}
-
-
/**
-
* What if the given name is already registered.
-
*
-
* @param Parameter $param
-
*
-
* @throws InvalidArgumentException If given param name is already registered.
-
*/
-
protected function ifAlreadyRegistered(Parameter $param): void
-
{
-
if ($this->registered($param->attributeName())) {
-
throw new InvalidParameterException(t(
-
'The parameter "%s" is already registered',
-
[$param instanceof Option ? $param->long() : $param->name()]
-
));
-
}
-
}
-
-
/**
-
* Check if either argument/option with given name is registered.
-
*/
-
public function registered($attribute): bool
-
{
-
return array_key_exists($attribute, $this->_values);
-
}
-
-
/**
-
* Get all options.
-
*
-
* @return Option[]
-
*/
-
public function allOptions(): array
-
{
-
return $this->_options;
-
}
-
-
/**
-
* Get all arguments.
-
*
-
* @return Argument[]
-
*/
-
public function allArguments(): array
-
{
-
return $this->_arguments;
-
}
-
-
/**
-
* Magic getter for specific value by its key.
-
*/
-
public function __get(string $key): mixed
-
{
-
return $this->_values[$key] ?? null;
-
}
-
-
/**
-
* Get the command arguments i.e which is not an option.
-
*/
-
public function args(): array
-
{
-
return array_diff_key($this->_values, $this->_options);
-
}
-
-
/**
-
* Get values indexed by camelized attribute name.
-
*/
-
public function values(bool $withDefaults = true): array
-
{
-
$values = $this->_values;
-
$values['version'] = $this->_version ?? null;
-
-
if (!$withDefaults) {
-
unset($values['help'], $values['version'], $values['verbosity']);
-
}
-
-
return $values;
-
}
-
}
-164
vendor/adhocore/cli/src/Input/Reader.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Input;
-
-
use function array_filter;
-
use function fgets;
-
use function fopen;
-
use function implode;
-
use function rtrim;
-
use function shell_exec;
-
use function stream_get_contents;
-
use function stream_select;
-
-
use const DIRECTORY_SEPARATOR;
-
use const PHP_EOL;
-
use const STDIN;
-
-
/**
-
* Cli Reader.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*/
-
class Reader
-
{
-
/** @var resource Input file handle */
-
protected $stream;
-
-
/**
-
* Constructor.
-
*
-
* @param string|null $path Read path. Defaults to STDIN.
-
*/
-
public function __construct(?string $path = null)
-
{
-
$this->stream = $path ? fopen($path, 'r') : STDIN;
-
}
-
-
/**
-
* Read a line from configured stream (or terminal).
-
*
-
* @param mixed $default The default value.
-
* @param callable|null $fn The validator/sanitizer callback.
-
*
-
* @return mixed
-
*/
-
public function read($default = null, ?callable $fn = null): mixed
-
{
-
$in = rtrim(fgets($this->stream), "\r\n");
-
-
if ('' === $in && null !== $default) {
-
return $default;
-
}
-
-
return $fn ? $fn($in) : $in;
-
}
-
-
/**
-
* Same like read but it reads all the lines.
-
*
-
* @codeCoverageIgnore
-
*
-
* @param callable|null $fn The validator/sanitizer callback.
-
*
-
* @return string
-
*/
-
public function readAll(?callable $fn = null): string
-
{
-
$in = stream_get_contents($this->stream);
-
-
return $fn ? $fn($in) : $in;
-
}
-
-
/**
-
* Read content piped to the stream without waiting.
-
*
-
* @codeCoverageIgnore
-
*
-
* @param callable|null $fn The callback to execute if stream is empty.
-
*
-
* @return string
-
*/
-
public function readPiped(?callable $fn = null): string
-
{
-
$stdin = '';
-
$read = [$this->stream];
-
$write = [];
-
$exept = [];
-
-
if (stream_select($read, $write, $exept, 0) === 1) {
-
while ($line = fgets($this->stream)) {
-
$stdin .= $line;
-
}
-
}
-
-
if ('' === $stdin) {
-
return $fn ? $fn($this) : '';
-
}
-
-
return $stdin;
-
}
-
-
/**
-
* Read a line from configured stream (or terminal) but don't echo it back.
-
*
-
* @param callable|null $fn The validator/sanitizer callback.
-
*
-
* @return mixed
-
*/
-
public function readHidden($default = null, ?callable $fn = null): mixed
-
{
-
// @codeCoverageIgnoreStart
-
if ('\\' === DIRECTORY_SEPARATOR) {
-
return $this->readHiddenWinOS($default, $fn);
-
}
-
// @codeCoverageIgnoreEnd
-
-
defined('RUNNING_TEST') || shell_exec('stty -echo');
-
$in = $this->read($default, $fn);
-
defined('RUNNING_TEST') || shell_exec('stty echo');
-
-
echo PHP_EOL;
-
-
return $in;
-
}
-
-
/**
-
* Read a line from configured stream (or terminal) but don't echo it back.
-
*
-
* @codeCoverageIgnore
-
*
-
* @param callable|null $fn The validator/sanitizer callback.
-
*
-
* @return mixed
-
*/
-
protected function readHiddenWinOS($default = null, ?callable $fn = null): mixed
-
{
-
$cmd = 'powershell -Command ' . implode('; ', array_filter([
-
'$pword = Read-Host -AsSecureString',
-
'$pword = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pword)',
-
'$pword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($pword)',
-
'echo $pword',
-
]));
-
-
$in = rtrim(shell_exec($cmd), "\r\n");
-
-
if ('' === $in && null !== $default) {
-
return $default;
-
}
-
-
return $fn ? $fn($in) : $in;
-
}
-
}
-289
vendor/adhocore/cli/src/Output/Color.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Output;
-
-
use Ahc\Cli\Exception\InvalidArgumentException;
-
-
use function Ahc\Cli\t;
-
use function array_intersect_key;
-
use function constant;
-
use function defined;
-
use function lcfirst;
-
use function method_exists;
-
use function preg_match_all;
-
use function str_ireplace;
-
use function str_replace;
-
use function stripos;
-
use function strtolower;
-
use function strtoupper;
-
use function strtr;
-
-
use const PHP_EOL;
-
-
/**
-
* Cli Colorizer.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link static https://github.com/adhocore/cli
-
*/
-
class Color
-
{
-
const BLACK = 30;
-
const RED = 31;
-
const GREEN = 32;
-
const YELLOW = 33;
-
const BLUE = 34;
-
const PURPLE = 35;
-
const CYAN = 36;
-
const WHITE = 37;
-
const GRAY = 47;
-
const DARKGRAY = 100;
-
-
public static bool $enabled = true;
-
-
protected string $format = "\033[:mod:;:fg:;:bg:m:txt:\033[0m";
-
-
/** @var array Custom styles */
-
protected static array $styles = [
-
'answer' => ['fg' => 37, 'mod' => 2],
-
'choice' => ['fg' => 36],
-
'comment' => ['fg' => 37, 'mod' => 2],
-
'error' => ['fg' => 31],
-
'help_category' => ['fg' => 32, 'mod' => 1],
-
'help_description_even' => ['fg' => 37, 'mod' => 2],
-
'help_description_odd' => ['fg' => 37, 'mod' => 2],
-
'help_example' => ['fg' => 33],
-
'help_footer' => ['fg' => 33],
-
'help_group' => ['fg' => 33, 'mod' => 1],
-
'help_header' => ['fg' => 37, 'mod' => 1],
-
'help_item_even' => ['fg' => 37, 'mod' => 1],
-
'help_item_odd' => ['fg' => 37, 'mod' => 1],
-
'help_summary' => ['fg' => 37, 'mod' => 2],
-
'help_text' => ['fg' => 37, 'mod' => 1],
-
'info' => ['fg' => 34],
-
'logo' => ['fg' => 37],
-
'ok' => ['fg' => 32],
-
'question' => ['fg' => 33],
-
'version' => ['fg' => 37, 'mod' => 1],
-
'warn' => ['fg' => 33],
-
];
-
-
/**
-
* Returns a line formatted as comment.
-
*/
-
public function comment(string $text, array $style = []): string
-
{
-
return $this->line($text, static::$styles['comment'] + $style);
-
}
-
-
/**
-
* Returns a line formatted as comment.
-
*/
-
public function error(string $text, array $style = []): string
-
{
-
return $this->line($text, static::$styles['error'] + $style);
-
}
-
-
/**
-
* Returns a line formatted as ok msg.
-
*/
-
public function ok(string $text, array $style = []): string
-
{
-
return $this->line($text, static::$styles['ok'] + $style);
-
}
-
-
/**
-
* Returns a line formatted as warning.
-
*/
-
public function warn(string $text, array $style = []): string
-
{
-
return $this->line($text, static::$styles['warn'] + $style);
-
}
-
-
/**
-
* Returns a line formatted as info.
-
*/
-
public function info(string $text, array $style = []): string
-
{
-
return $this->line($text, static::$styles['info'] + $style);
-
}
-
-
/**
-
* Returns the color code for a 256 background color.
-
*/
-
public static function bg256(int $code): string
-
{
-
return "48;5;{$code}";
-
}
-
-
/**
-
* Returns the color code for a 256 foreground color.
-
*/
-
public static function fg256(int $code): string
-
{
-
return "38;5;{$code}";
-
}
-
-
/**
-
* Returns a formatted/colored line.
-
*/
-
public function line(string $text, array $style = []): string
-
{
-
if (!self::$enabled || getenv('NO_COLOR')) {
-
return $text;
-
}
-
-
$style += ['bg' => null, 'fg' => static::WHITE, 'bold' => 0, 'mod' => null];
-
-
$format = $style['bg'] === null
-
? str_replace(';:bg:', '', $this->format)
-
: $this->format;
-
-
$line = strtr($format, [
-
':mod:' => (int) ($style['mod'] ?? $style['bold']),
-
':fg:' => $style['fg'],
-
':bg:' => is_int($style['bg']) ? ($style['bg'] + 10) : $style['bg'],
-
':txt:' => $text,
-
]);
-
-
return $line;
-
}
-
-
/**
-
* Prepare a multi colored string with html like tags.
-
*
-
* Example: "<errorBold>Text</end><eol/><bgGreenBold>Text</end><eol>"
-
*/
-
public function colors(string $text): string
-
{
-
$text = str_replace(['<eol>', '<eol/>', '</eol>', "\r\n", "\n"], '__PHP_EOL__', $text);
-
-
if (!preg_match_all('/<(\w+)>(.*?)<\/end>/', $text, $matches)) {
-
return str_replace('__PHP_EOL__', PHP_EOL, $text);
-
}
-
-
$end = "\033[0m";
-
$text = str_replace(['<end>', '</end>'], $end, $text);
-
-
foreach ($matches[1] as $i => $method) {
-
$part = str_replace($end, '', $this->{$method}(''));
-
$text = str_replace("<$method>", $part, $text);
-
}
-
-
return str_replace('__PHP_EOL__', PHP_EOL, $text);
-
}
-
-
/**
-
* Register a custom style.
-
*
-
* @param string $name Example: 'alert'
-
* @param array $style Example: ['fg' => Color::RED, 'bg' => Color::YELLOW, 'bold' => 1]
-
*
-
* @return void
-
*/
-
public static function style(string $name, array $style): void
-
{
-
$allow = ['fg' => true, 'bg' => true, 'bold' => true];
-
$style = array_intersect_key($style, $allow);
-
-
if (empty($style)) {
-
throw new InvalidArgumentException(t('Trying to set empty or invalid style'));
-
}
-
-
$invisible = (isset($style['bg']) && isset($style['fg']) && $style['bg'] === $style['fg']);
-
if ($invisible && method_exists(static::class, $name)) {
-
throw new InvalidArgumentException(t('Built-in styles cannot be invisible'));
-
}
-
-
static::$styles[$name] = $style;
-
}
-
-
/**
-
* Magically build styles.
-
*
-
* @param string $name Example: 'boldError', 'bgGreenBold' etc
-
* @param array $arguments
-
*
-
* @return string
-
*/
-
public function __call(string $name, array $arguments): string
-
{
-
if (!isset($arguments[0])) {
-
throw new InvalidArgumentException(t('Text required'));
-
}
-
-
[$name, $text, $style] = $this->parseCall($name, $arguments);
-
-
if (isset(static::$styles[$name])) {
-
return $this->line($text, static::$styles[$name] + $style);
-
}
-
-
if (defined($color = static::class . '::' . strtoupper($name))) {
-
$name = 'line';
-
$style += ['fg' => constant($color)];
-
}
-
-
if (!method_exists($this, $name)) {
-
throw new InvalidArgumentException(t('Style "%s" not defined', [$name]));
-
}
-
-
return $this->{$name}($text, $style);
-
}
-
-
/**
-
* Parse the name argument pairs to determine callable method and style params.
-
*/
-
protected function parseCall(string $name, array $arguments): array
-
{
-
[$text, $style] = $arguments + ['', []];
-
-
$mods = ['bold' => 1, 'dim' => 2, 'italic' => 3, 'underline' => 4, 'flash' => 5];
-
-
foreach ($mods as $mod => $value) {
-
if (stripos($name, $mod) !== false) {
-
$name = str_ireplace($mod, '', $name);
-
$style += ['bold' => $value];
-
}
-
}
-
-
if (isset(static::$styles[strtolower($name)])) {
-
$name = strtolower($name);
-
}
-
-
if (!preg_match_all('/([b|B|f|F]g)?([A-Z][a-z]+)([^A-Z])?/', $name, $matches)) {
-
return [lcfirst($name) ?: 'line', $text, $style];
-
}
-
-
[$name, $style] = $this->buildStyle($name, $style, $matches);
-
-
return [$name, $text, $style];
-
}
-
-
/**
-
* Build style parameter from matching combination.
-
*/
-
protected function buildStyle(string $name, array $style, array $matches): array
-
{
-
foreach ($matches[0] as $i => $match) {
-
$name = str_replace($match, '', $name);
-
$type = strtolower($matches[1][$i]) ?: 'fg';
-
-
if (defined($color = static::class . '::' . strtoupper($matches[2][$i]))) {
-
$style += [$type => constant($color)];
-
}
-
}
-
-
return [lcfirst($name) ?: 'line', $style];
-
}
-
}
-139
vendor/adhocore/cli/src/Output/Cursor.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Output;
-
-
use function max;
-
use function sprintf;
-
use function str_repeat;
-
-
/**
-
* Cli Cursor.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link static https://github.com/adhocore/cli
-
*/
-
class Cursor
-
{
-
/**
-
* Returns signal to move cursor up `n` times.
-
*
-
* @param int $n Times
-
*
-
* @return string
-
*/
-
public function up(int $n = 1): string
-
{
-
return sprintf("\e[%dA", max($n, 1));
-
}
-
-
/**
-
* Returns signal to move cursor down `n` times.
-
*
-
* @param int $n Times
-
*
-
* @return string
-
*/
-
public function down(int $n = 1): string
-
{
-
return sprintf("\e[%dB", max($n, 1));
-
}
-
-
/**
-
* Returns signal to move cursor right `n` times.
-
*
-
* @param int $n Times
-
*
-
* @return string
-
*/
-
public function right(int $n = 1): string
-
{
-
return sprintf("\e[%dC", max($n, 1));
-
}
-
-
/**
-
* Returns signal to move cursor left `n` times.
-
*
-
* @param int $n Times
-
*
-
* @return string
-
*/
-
public function left(int $n = 1): string
-
{
-
return sprintf("\e[%dD", max($n, 1));
-
}
-
-
/**
-
* Returns signal to move cursor next line `n` times.
-
*
-
* @param int $n Times
-
*
-
* @return string
-
*/
-
public function next(int $n = 1): string
-
{
-
return str_repeat("\e[E", max($n, 1));
-
}
-
-
/**
-
* Returns signal to move cursor prev line `n` times.
-
*
-
* @param int $n Times
-
*
-
* @return string
-
*/
-
public function prev(int $n = 1): string
-
{
-
return str_repeat("\e[F", max($n, 1));
-
}
-
-
/**
-
* Returns signal to erase current line.
-
*/
-
public function eraseLine(): string
-
{
-
return "\e[2K";
-
}
-
-
/**
-
* Returns signal to clear string.
-
*/
-
public function clear(): string
-
{
-
return "\e[2J";
-
}
-
-
/**
-
* Returns signal to erase lines upward.
-
*/
-
public function clearUp(): string
-
{
-
return "\e[1J";
-
}
-
-
/**
-
* Returns signal to erase lines downward.
-
*/
-
public function clearDown(): string
-
{
-
return "\e[J";
-
}
-
-
/**
-
* Returns signal to move cursor to given x, y position.
-
*/
-
public function moveTo(int $x, int $y): string
-
{
-
return sprintf("\e[%d;%dH", $y, $x);
-
}
-
}
-376
vendor/adhocore/cli/src/Output/ProgressBar.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Output;
-
-
use Ahc\Cli\Helper\Terminal;
-
use UnexpectedValueException;
-
-
use function Ahc\Cli\t;
-
use function count;
-
use function implode;
-
use function in_array;
-
use function iterator_to_array;
-
use function min;
-
use function round;
-
use function str_repeat;
-
use function strlen;
-
use function trim;
-
-
/**
-
* The Progress provides helpers to display progress output.
-
*
-
* @author Dimitri Sitchet Tomkeu <devcode.dst@gmail.com>
-
*/
-
class ProgressBar
-
{
-
/**
-
* The total number of items involved.
-
*/
-
protected int $total = 0;
-
-
/**
-
* The current item that the progress bar represents.
-
*/
-
protected int $current = 0;
-
-
/**
-
* The current percentage displayed.
-
*/
-
protected string $currentPercentage = '';
-
-
/**
-
* The string length of the bar when at 100%.
-
*/
-
protected int $barStrLen = 0;
-
-
/**
-
* Flag indicating whether we are writing the bar for the first time.
-
*/
-
protected bool $firstLine = true;
-
-
/**
-
* Current status bar label.
-
*/
-
protected string $label = '';
-
-
/**
-
* Options for progress bar.
-
*/
-
private array $options = [
-
'pointer' => '>',
-
'loader' => '=',
-
'color' => 'white',
-
'labelColor' => 'white',
-
'labelPosition' => 'bottom',
-
// in spinner/async mode, you may hide the progress percentage as you won't know in advance how long it will take
-
'showPercentage' => true,
-
];
-
-
/**
-
* Force a redraw every time.
-
*/
-
protected bool $forceRedraw = false;
-
-
/**
-
* If this progress bar ever displayed a label.
-
*/
-
protected bool $hasLabelLine = false;
-
-
protected Writer $writer;
-
-
protected Cursor $cursor;
-
-
protected Terminal $terminal;
-
-
/**
-
* If they pass in a total, set the total.
-
*/
-
public function __construct(?int $total = null, ?Writer $writer = null)
-
{
-
if ($total !== null) {
-
$this->total($total);
-
}
-
-
$this->writer = $writer ?: new Writer();
-
$this->cursor = $this->writer->cursor();
-
$this->terminal = $this->writer->terminal();
-
}
-
-
/**
-
* Set the total property.
-
*/
-
public function total(int $total): self
-
{
-
$this->total = $total;
-
-
return $this;
-
}
-
-
/**
-
* Set the string length of the bar when at 100%.
-
*
-
* @internal use by Spinner
-
*/
-
public function barWidth(int $size): self
-
{
-
$this->barStrLen = max(1, $size);
-
-
return $this;
-
}
-
-
/**
-
* Set progress bar options.
-
*/
-
public function option(string|array $key, ?string $value = null): self
-
{
-
if (is_string($key)) {
-
if (empty($value)) {
-
throw new UnexpectedValueException(t('Configuration option value is required'));
-
}
-
-
$key = [$key => $value];
-
}
-
-
$this->options = array_merge($this->options, $key);
-
-
return $this;
-
}
-
-
/**
-
* Force end of progress.
-
*/
-
public function finish(): void
-
{
-
$this->current = $this->total;
-
}
-
-
/**
-
* Determines the current percentage we are at and re-writes the progress bar.
-
*
-
* @throws UnexpectedValueException
-
*
-
* @return void
-
*/
-
public function current(int $current, string $label = '')
-
{
-
if ($this->total == 0) {
-
// Avoid dividing by 0
-
throw new UnexpectedValueException(t('The progress total must be greater than zero.'));
-
}
-
-
if ($current > $this->total) {
-
throw new UnexpectedValueException(
-
t('The current (%1$d) is greater than the total (%2$d).', [$current, $this->total])
-
);
-
}
-
-
$this->drawProgressBar($current, $label);
-
-
$this->current = $current;
-
$this->label = $label;
-
}
-
-
/**
-
* Increments the current position we are at and re-writes the progress bar.
-
*
-
* @param int $increment The number of items to increment by
-
*/
-
public function advance(int $increment = 1, string $label = '')
-
{
-
$this->current($this->current + $increment, $label);
-
}
-
-
/**
-
* Force the progress bar to redraw every time regardless of whether it has changed or not.
-
*/
-
public function forceRedraw(bool $force = true): self
-
{
-
$this->forceRedraw = $force;
-
-
return $this;
-
}
-
-
/**
-
* Update a progress bar using an iterable.
-
*
-
* @param iterable $items Array or any other iterable object
-
* @param callable $callback A handler to run on each item
-
*/
-
public function each($items, ?callable $callback = null)
-
{
-
if ($items instanceof \Traversable) {
-
$items = iterator_to_array($items);
-
}
-
-
if (0 === $total = count($items)) {
-
return;
-
}
-
-
$this->total($total);
-
-
foreach ($items as $key => $item) {
-
$label = $callback ? (string) $callback($item, $key) : '';
-
-
$this->advance(1, $label);
-
}
-
}
-
-
/**
-
* Draw the progress bar, if necessary.
-
*/
-
protected function drawProgressBar(int $current, string $label)
-
{
-
$percentage = $this->percentageFormatted($current / $this->total);
-
-
if ($this->shouldRedraw($percentage, $label)) {
-
$this->writer->colors($this->getProgressBar($current, $label) . '<eol>');
-
}
-
-
$this->currentPercentage = $percentage;
-
}
-
-
/**
-
* Build the progress bar str and return it.
-
*/
-
protected function getProgressBar(int $current, string $label): string
-
{
-
if ($this->firstLine) {
-
// Drop down a line, we are about to
-
// re-write this line for the progress bar
-
$this->writer->write('');
-
$this->firstLine = false;
-
}
-
-
// Move the cursor up and clear it to the end
-
$lines = $this->hasLabelLine ? 2 : 1;
-
$bar = $this->cursor->up($lines);
-
$bar .= $this->cr() . $this->cursor->eraseLine();
-
$bar .= $this->getProgressBarStr($current, $label);
-
-
// If this line has a label then set that this progress bar has a label line
-
if (strlen($label) > 0 && in_array($this->options['labelPosition'], ['bottom', 'top'], true)) {
-
$this->hasLabelLine = true;
-
}
-
-
return $bar;
-
}
-
-
/**
-
* Get the progress bar string, basically:
-
* =============> 50% label.
-
*/
-
protected function getProgressBarStr(int $current, string $label): string
-
{
-
$percentage = $current / $this->total;
-
$bar_length = round($this->getBarStrLen() * $percentage);
-
$bar = $this->getBar($bar_length);
-
$number = $this->percentageFormatted($percentage);
-
-
if ($label) {
-
$label = $this->labelFormatted($label);
-
// If this line doesn't have a label, but we've had one before,
-
// then ensure the label line is cleared
-
} elseif ($this->hasLabelLine) {
-
$label = $this->labelFormatted('');
-
}
-
-
if (in_array($this->options['labelPosition'], ['left', 'right', 'top'], true)) {
-
$label = trim($label);
-
}
-
-
return $this->progressBarFormatted($bar, $number, $label);
-
}
-
-
/**
-
* Get the string for the actual bar based on the current length.
-
*/
-
protected function getBar(int $length): string
-
{
-
$bar = str_repeat($this->options['loader'], max(1, $length));
-
$padding = str_repeat(' ', max(1, $this->getBarStrLen() - $length));
-
-
return "{$bar}{$this->options['pointer']}{$padding}";
-
}
-
-
/**
-
* Get the length of the bar string based on the width of the terminal window.
-
*/
-
protected function getBarStrLen(): int
-
{
-
if (!$this->barStrLen) {
-
// Subtract 10 because of the '> 100%' plus some padding, max 100
-
$this->barStrLen = max(50, min($this->terminal->width() - 10, 100));
-
}
-
-
return $this->barStrLen;
-
}
-
-
/**
-
* Format the percentage so it looks pretty.
-
*/
-
protected function percentageFormatted(float $percentage): string
-
{
-
return round($percentage * 100) . '%';
-
}
-
-
/**
-
* Format the label so it is positioned correctly.
-
*/
-
protected function labelFormatted(string $label): string
-
{
-
return "\n" . $label;
-
}
-
-
/**
-
* Format the output of the progress bar by placing the label in the right place (top, right, bottom or left).
-
*/
-
protected function progressBarFormatted(string $bar, string $number, string $label): string
-
{
-
if (!$this->options['showPercentage']) {
-
$number = '';
-
}
-
-
$progress = [];
-
if ($this->options['labelPosition'] === 'left') {
-
// display : ====> Label 50%
-
$progress[] = '<' . $this->options['color'] . '>' . $bar . '</end> ';
-
$progress[] = '<' . $this->options['labelColor'] . '>' . $label . '</end> ';
-
$progress[] = '<' . $this->options['color'] . '>' . $number . '</end>';
-
} elseif ($this->options['labelPosition'] === 'top') {
-
// display :Label
-
// ====> 50%
-
$progress[] = '<' . $this->options['labelColor'] . '>' . $label . "\n" . '</end>';
-
$progress[] = '<' . $this->options['color'] . '>' . $bar . ' ' . $number . '</end>'; // bar + percentage
-
} else {
-
// display (on right) : ====> 50% Label
-
// display (on bottom): ====> 50%
-
// Label
-
$progress[] = '<' . $this->options['color'] . '>' . $bar . ' ' . $number . '</end> '; // bar + percentage
-
$progress[] = '<' . $this->options['labelColor'] . '>' . $label . '</end>';
-
}
-
-
return implode('', $progress);
-
}
-
-
/**
-
* Determine whether the progress bar has changed and we need to redrew.
-
*/
-
protected function shouldRedraw(string $percentage, string $label): bool
-
{
-
return $this->forceRedraw || $percentage != $this->currentPercentage || $label != $this->label;
-
}
-
-
protected function cr(): string
-
{
-
return Terminal::isWindows() ? "\r" : '';
-
}
-
}
-189
vendor/adhocore/cli/src/Output/Table.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Output;
-
-
use Ahc\Cli\Exception\InvalidArgumentException;
-
use Ahc\Cli\Helper\InflectsString;
-
-
use function Ahc\Cli\t;
-
use function array_column;
-
use function array_fill_keys;
-
use function array_keys;
-
use function array_map;
-
use function array_merge;
-
use function gettype;
-
use function implode;
-
use function is_array;
-
use function max;
-
use function reset;
-
use function str_repeat;
-
use function trim;
-
-
use const PHP_EOL;
-
-
class Table
-
{
-
use InflectsString;
-
-
public function render(array $rows, array $styles = []): string
-
{
-
if ([] === $table = $this->normalize($rows)) {
-
return '';
-
}
-
-
[$head, $rows] = $table;
-
-
$styles = $this->normalizeStyles($styles);
-
$title = $body = $dash = $positions = [];
-
-
[$start, $end] = $styles['head'];
-
$pos = 0;
-
foreach ($head as $col => $size) {
-
$dash[] = str_repeat('-', $size + 2);
-
$title[] = $this->strPad($this->toWords($col), $size, ' ');
-
$positions[$col] = ++$pos;
-
}
-
-
$title = "|$start " . implode(" $end|$start ", $title) . " $end|" . PHP_EOL;
-
-
$odd = true;
-
foreach ($rows as $line => $row) {
-
$parts = [];
-
$line++;
-
-
foreach ($head as $col => $size) {
-
$colNumber = $positions[$col];
-
-
if (isset($styles[$line . ':' . $colNumber])) { // cell, 1:1
-
$style = $styles[$line . ':' . $colNumber];
-
} elseif (isset($styles[$col]) || isset($styles['*:' . $colNumber])) { // col, *:2 or b
-
$style = $styles['*:' . $colNumber] ?? $styles[$col];
-
} elseif (isset($styles[$line . ':*'])) { // row, 2:*
-
$style = $styles[$line . ':*'];
-
} elseif (isset($styles['*:*'])) { // any cell, *:*
-
$style = $styles['*:*'];
-
} else {
-
$style = $styles[['even', 'odd'][(int) $odd]];
-
}
-
-
$text = $row[$col] ?? '';
-
[$start, $end] = $this->parseStyle($style, $text, $row, $rows);
-
-
if (preg_match('/(\\x1b(?:.+)m)/U', $text, $matches)) {
-
$word = str_replace($matches[1], '', $text);
-
$word = preg_replace('/\\x1b\[0m/', '', $word);
-
-
$size += $this->strwidth($text) - $this->strwidth($word);
-
}
-
-
$parts[] = "$start " . $this->strPad($text, $size, ' ') . " $end";
-
}
-
-
$odd = !$odd;
-
$body[] = '|' . implode('|', $parts) . '|';
-
}
-
-
$dash = '+' . implode('+', $dash) . '+' . PHP_EOL;
-
$body = implode(PHP_EOL, $body) . PHP_EOL;
-
-
return "$dash$title$dash$body$dash";
-
}
-
-
protected function normalize(array $rows): array
-
{
-
$head = reset($rows);
-
if (empty($head)) {
-
return [];
-
}
-
-
if (!is_array($head)) {
-
throw new InvalidArgumentException(
-
t('Rows must be array of assoc arrays, %s given', [gettype($head)])
-
);
-
}
-
-
$head = array_fill_keys(array_keys($head), null);
-
foreach ($rows as $i => &$row) {
-
$row = array_merge($head, $row);
-
}
-
-
foreach ($head as $col => &$value) {
-
$cols = array_column($rows, $col);
-
$cols = array_map(function ($col) {
-
$col ??= '';
-
-
if (preg_match('/(\\x1b(?:.+)m)/U', $col, $matches)) {
-
$col = str_replace($matches[1], '', $col);
-
$col = preg_replace('/\\x1b\[0m/', '', $col);
-
}
-
-
return $col;
-
}, $cols);
-
-
$span = array_map([$this, 'strwidth'], $cols);
-
$span[] = $this->strwidth($col);
-
$value = max($span);
-
}
-
-
return [$head, $rows];
-
}
-
-
protected function normalizeStyles(array $styles): array
-
{
-
$default = [
-
// styleFor => ['styleStartFn', 'end']
-
'head' => ['', ''],
-
'odd' => ['', ''],
-
'even' => ['', ''],
-
];
-
-
foreach ($styles as $for => $style) {
-
if (is_string($style) && $style !== '') {
-
$default[$for] = ['<' . trim($style, '<> ') . '>', '</end>'];
-
} elseif (str_contains($for, ':') && is_callable($style)) {
-
$default[$for] = $style;
-
}
-
}
-
-
return $default;
-
}
-
-
protected function parseStyle(array|callable $style, $val, array $row, array $table): array
-
{
-
if (is_array($style)) {
-
return $style;
-
}
-
-
$style = call_user_func($style, $val, $row, $table);
-
-
if (is_string($style) && $style !== '') {
-
return ['<' . trim($style, '<> ') . '>', '</end>'];
-
}
-
if (is_array($style) && count($style) === 2) {
-
return $style;
-
}
-
-
return ['', ''];
-
}
-
-
/**
-
* Pad a multibyte string to a certain length with another multibyte string.
-
*/
-
protected function strPad(string $string, int $length, string $pad_string = ' '): string
-
{
-
if (1 > $paddingRequired = $length - $this->strwidth($string)) {
-
return $string;
-
}
-
-
return $string . $this->substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired);
-
}
-
}
-378
vendor/adhocore/cli/src/Output/Writer.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli\Output;
-
-
use Ahc\Cli\Helper\InflectsString;
-
use Ahc\Cli\Helper\Terminal;
-
-
use function fopen;
-
use function fwrite;
-
use function max;
-
use function method_exists;
-
use function str_repeat;
-
use function stripos;
-
use function strpos;
-
use function ucfirst;
-
-
use const PHP_EOL;
-
use const STDERR;
-
use const STDOUT;
-
-
/**
-
* Cli Writer.
-
*
-
* @author Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* @license MIT
-
*
-
* @link https://github.com/adhocore/cli
-
*
-
* @method Writer answer($text, $eol = false)
-
* @method Writer bgBlack($text, $eol = false)
-
* @method Writer bgBlue($text, $eol = false)
-
* @method Writer bgCyan($text, $eol = false)
-
* @method Writer bgGreen($text, $eol = false)
-
* @method Writer bgPurple($text, $eol = false)
-
* @method Writer bgRed($text, $eol = false)
-
* @method Writer bgWhite($text, $eol = false)
-
* @method Writer bgYellow($text, $eol = false)
-
* @method Writer black($text, $eol = false)
-
* @method Writer blackBgBlue($text, $eol = false)
-
* @method Writer blackBgCyan($text, $eol = false)
-
* @method Writer blackBgGreen($text, $eol = false)
-
* @method Writer blackBgPurple($text, $eol = false)
-
* @method Writer blackBgRed($text, $eol = false)
-
* @method Writer blackBgWhite($text, $eol = false)
-
* @method Writer blackBgYellow($text, $eol = false)
-
* @method Writer blue($text, $eol = false)
-
* @method Writer blueBgBlack($text, $eol = false)
-
* @method Writer blueBgCyan($text, $eol = false)
-
* @method Writer blueBgGreen($text, $eol = false)
-
* @method Writer blueBgPurple($text, $eol = false)
-
* @method Writer blueBgRed($text, $eol = false)
-
* @method Writer blueBgWhite($text, $eol = false)
-
* @method Writer blueBgYellow($text, $eol = false)
-
* @method Writer bold($text, $eol = false)
-
* @method Writer boldBlack($text, $eol = false)
-
* @method Writer boldBlackBgBlue($text, $eol = false)
-
* @method Writer boldBlackBgCyan($text, $eol = false)
-
* @method Writer boldBlackBgGreen($text, $eol = false)
-
* @method Writer boldBlackBgPurple($text, $eol = false)
-
* @method Writer boldBlackBgRed($text, $eol = false)
-
* @method Writer boldBlackBgWhite($text, $eol = false)
-
* @method Writer boldBlackBgYellow($text, $eol = false)
-
* @method Writer boldBlue($text, $eol = false)
-
* @method Writer boldBlueBgBlack($text, $eol = false)
-
* @method Writer boldBlueBgCyan($text, $eol = false)
-
* @method Writer boldBlueBgGreen($text, $eol = false)
-
* @method Writer boldBlueBgPurple($text, $eol = false)
-
* @method Writer boldBlueBgRed($text, $eol = false)
-
* @method Writer boldBlueBgWhite($text, $eol = false)
-
* @method Writer boldBlueBgYellow($text, $eol = false)
-
* @method Writer boldCyan($text, $eol = false)
-
* @method Writer boldCyanBgBlack($text, $eol = false)
-
* @method Writer boldCyanBgBlue($text, $eol = false)
-
* @method Writer boldCyanBgGreen($text, $eol = false)
-
* @method Writer boldCyanBgPurple($text, $eol = false)
-
* @method Writer boldCyanBgRed($text, $eol = false)
-
* @method Writer boldCyanBgWhite($text, $eol = false)
-
* @method Writer boldCyanBgYellow($text, $eol = false)
-
* @method Writer boldGreen($text, $eol = false)
-
* @method Writer boldGreenBgBlack($text, $eol = false)
-
* @method Writer boldGreenBgBlue($text, $eol = false)
-
* @method Writer boldGreenBgCyan($text, $eol = false)
-
* @method Writer boldGreenBgPurple($text, $eol = false)
-
* @method Writer boldGreenBgRed($text, $eol = false)
-
* @method Writer boldGreenBgWhite($text, $eol = false)
-
* @method Writer boldGreenBgYellow($text, $eol = false)
-
* @method Writer boldPurple($text, $eol = false)
-
* @method Writer boldPurpleBgBlack($text, $eol = false)
-
* @method Writer boldPurpleBgBlue($text, $eol = false)
-
* @method Writer boldPurpleBgCyan($text, $eol = false)
-
* @method Writer boldPurpleBgGreen($text, $eol = false)
-
* @method Writer boldPurpleBgRed($text, $eol = false)
-
* @method Writer boldPurpleBgWhite($text, $eol = false)
-
* @method Writer boldPurpleBgYellow($text, $eol = false)
-
* @method Writer boldRed($text, $eol = false)
-
* @method Writer boldRedBgBlack($text, $eol = false)
-
* @method Writer boldRedBgBlue($text, $eol = false)
-
* @method Writer boldRedBgCyan($text, $eol = false)
-
* @method Writer boldRedBgGreen($text, $eol = false)
-
* @method Writer boldRedBgPurple($text, $eol = false)
-
* @method Writer boldRedBgWhite($text, $eol = false)
-
* @method Writer boldRedBgYellow($text, $eol = false)
-
* @method Writer boldWhite($text, $eol = false)
-
* @method Writer boldWhiteBgBlack($text, $eol = false)
-
* @method Writer boldWhiteBgBlue($text, $eol = false)
-
* @method Writer boldWhiteBgCyan($text, $eol = false)
-
* @method Writer boldWhiteBgGreen($text, $eol = false)
-
* @method Writer boldWhiteBgPurple($text, $eol = false)
-
* @method Writer boldWhiteBgRed($text, $eol = false)
-
* @method Writer boldWhiteBgYellow($text, $eol = false)
-
* @method Writer boldYellow($text, $eol = false)
-
* @method Writer boldYellowBgBlack($text, $eol = false)
-
* @method Writer boldYellowBgBlue($text, $eol = false)
-
* @method Writer boldYellowBgCyan($text, $eol = false)
-
* @method Writer boldYellowBgGreen($text, $eol = false)
-
* @method Writer boldYellowBgPurple($text, $eol = false)
-
* @method Writer boldYellowBgRed($text, $eol = false)
-
* @method Writer boldYellowBgWhite($text, $eol = false)
-
* @method Writer choice($text, $eol = false)
-
* @method Writer colors($text)
-
* @method Writer comment($text, $eol = false)
-
* @method Writer cyan($text, $eol = false)
-
* @method Writer cyanBgBlack($text, $eol = false)
-
* @method Writer cyanBgBlue($text, $eol = false)
-
* @method Writer cyanBgGreen($text, $eol = false)
-
* @method Writer cyanBgPurple($text, $eol = false)
-
* @method Writer cyanBgRed($text, $eol = false)
-
* @method Writer cyanBgWhite($text, $eol = false)
-
* @method Writer cyanBgYellow($text, $eol = false)
-
* @method Writer error($text, $eol = false)
-
* @method Writer green($text, $eol = false)
-
* @method Writer greenBgBlack($text, $eol = false)
-
* @method Writer greenBgBlue($text, $eol = false)
-
* @method Writer greenBgCyan($text, $eol = false)
-
* @method Writer greenBgPurple($text, $eol = false)
-
* @method Writer greenBgRed($text, $eol = false)
-
* @method Writer greenBgWhite($text, $eol = false)
-
* @method Writer greenBgYellow($text, $eol = false)
-
* @method Writer help_category($text, $eol = false)
-
* @method Writer help_description_even($text, $eol = false)
-
* @method Writer help_description_odd($text, $eol = false)
-
* @method Writer help_example($text, $eol = false)
-
* @method Writer help_footer($text, $eol = false)
-
* @method Writer help_group($text, $eol = false)
-
* @method Writer help_header($text, $eol = false)
-
* @method Writer help_item_even($text, $eol = false)
-
* @method Writer help_item_odd($text, $eol = false)
-
* @method Writer help_summary($text, $eol = false)
-
* @method Writer help_text($text, $eol = false)
-
* @method Writer info($text, $eol = false)
-
* @method Writer logo($text, $eol = false)
-
* @method Writer ok($text, $eol = false)
-
* @method Writer purple($text, $eol = false)
-
* @method Writer purpleBgBlack($text, $eol = false)
-
* @method Writer purpleBgBlue($text, $eol = false)
-
* @method Writer purpleBgCyan($text, $eol = false)
-
* @method Writer purpleBgGreen($text, $eol = false)
-
* @method Writer purpleBgRed($text, $eol = false)
-
* @method Writer purpleBgWhite($text, $eol = false)
-
* @method Writer purpleBgYellow($text, $eol = false)
-
* @method Writer question($text, $eol = false)
-
* @method Writer red($text, $eol = false)
-
* @method Writer redBgBlack($text, $eol = false)
-
* @method Writer redBgBlue($text, $eol = false)
-
* @method Writer redBgCyan($text, $eol = false)
-
* @method Writer redBgGreen($text, $eol = false)
-
* @method Writer redBgPurple($text, $eol = false)
-
* @method Writer redBgWhite($text, $eol = false)
-
* @method Writer redBgYellow($text, $eol = false)
-
* @method Writer version($text, $eol = false)
-
* @method Writer warn($text, $eol = false)
-
* @method Writer white($text, $eol = false)
-
* @method Writer yellow($text, $eol = false)
-
* @method Writer yellowBgBlack($text, $eol = false)
-
* @method Writer yellowBgBlue($text, $eol = false)
-
* @method Writer yellowBgCyan($text, $eol = false)
-
* @method Writer yellowBgGreen($text, $eol = false)
-
* @method Writer yellowBgPurple($text, $eol = false)
-
* @method Writer yellowBgRed($text, $eol = false)
-
* @method Writer yellowBgWhite($text, $eol = false)
-
*/
-
class Writer
-
{
-
use InflectsString;
-
-
/** @var resource Output file handle */
-
protected $stream;
-
-
/** @var resource Error output file handle */
-
protected $eStream;
-
-
protected ?string $method = null;
-
-
protected Color $colorizer;
-
-
protected Cursor $cursor;
-
-
protected Terminal $terminal;
-
-
public function __construct(?string $path = null, ?Color $colorizer = null)
-
{
-
if ($path) {
-
$path = fopen($path, 'w');
-
}
-
-
$this->stream = $path ?: STDOUT;
-
$this->eStream = $path ?: STDERR;
-
-
$this->cursor = new Cursor;
-
$this->colorizer = $colorizer ?? new Color;
-
$this->terminal = new Terminal();
-
}
-
-
/**
-
* Get Colorizer.
-
*/
-
public function colorizer(): Color
-
{
-
return $this->colorizer;
-
}
-
-
/**
-
* Get Cursor.
-
*/
-
public function cursor(): Cursor
-
{
-
return $this->cursor;
-
}
-
-
/**
-
* Get Terminal.
-
*/
-
public function terminal(): Terminal
-
{
-
return $this->terminal;
-
}
-
-
/**
-
* Magically set methods.
-
*
-
* @param string $name Like `red`, `bgRed`, 'bold', `error` etc
-
*
-
* @return self
-
*/
-
public function __get(string $name): self
-
{
-
if ($this->method === null || strpos($this->method, $name) === false) {
-
$this->method .= $this->method ? ucfirst($name) : $name;
-
}
-
-
return $this;
-
}
-
-
/**
-
* Write the formatted text to stdout or stderr.
-
*/
-
public function write(string $text, bool $eol = false): self
-
{
-
[$method, $this->method] = [$this->method ?: 'line', ''];
-
-
$text = $this->colorizer->{$method}($text, []);
-
$error = stripos($method, 'error') !== false;
-
-
if ($eol) {
-
$text .= PHP_EOL;
-
}
-
-
return $this->doWrite($text, $error);
-
}
-
-
/**
-
* Really write to the stream.
-
*/
-
protected function doWrite(string $text, bool $error = false): self
-
{
-
$stream = $error ? $this->eStream : $this->stream;
-
-
fwrite($stream, $text);
-
-
return $this;
-
}
-
-
/**
-
* Write EOL n times.
-
*/
-
public function eol(int $n = 1): self
-
{
-
return $this->doWrite(str_repeat(PHP_EOL, max($n, 1)));
-
}
-
-
/**
-
* Write raw text (as it is).
-
*/
-
public function raw($text, bool $error = false): self
-
{
-
return $this->doWrite((string) $text, $error);
-
}
-
-
/**
-
* Generate table for the console. Keys of first row are taken as header.
-
*
-
* @param array[] $rows Array of assoc arrays.
-
* @param array $styles Eg: ['head' => 'bold', 'odd' => 'comment', 'even' => 'green']
-
*
-
* @return self
-
*/
-
public function table(array $rows, array $styles = []): self
-
{
-
$table = (new Table)->render($rows, $styles);
-
-
return $this->colors($table);
-
}
-
-
/**
-
* writes a key/value set to two columns in a row.
-
*
-
* @example PHP Version ............................................................. 8.1.4
-
*
-
* @param string $first The text to write in left side
-
* @param string|null $second The text to write in right side
-
* @param array $options Options to use when writing Eg: ['fg' => Color::GREEN, 'bold' => 1, 'sep' => '-']
-
*
-
* @return self
-
*/
-
public function justify(string $first, ?string $second = null, array $options = []): self
-
{
-
$options = [
-
'first' => ($options['first'] ?? []) + ['bg' => null, 'fg' => Color::WHITE, 'bold' => 0],
-
'second' => ($options['second'] ?? []) + ['bg' => null, 'fg' => Color::WHITE, 'bold' => 1],
-
'sep' => $options['sep'] ?? '.',
-
];
-
-
$second = (string) $second;
-
$terminalWidth = $this->terminal->width() ?? 80;
-
$dashWidth = $terminalWidth - ($this->strwidth($first) + $this->strwidth($second));
-
// remove left and right margins because we're going to add 1 space on each side (after/before the text).
-
// if we don't have a second element, we just remove the left margin
-
$dashWidth -= $second === '' ? 1 : 2;
-
-
$first = $this->colorizer->line($first, $options['first']);
-
if ($second !== '') {
-
$second = $this->colorizer->line($second, $options['second']);
-
}
-
-
$sep = $dashWidth >= 0 ? str_repeat((string) $options['sep'], $dashWidth) : '';
-
$this->write($first . ' ' . $sep . ' ' . $second);
-
-
return $this->eol();
-
}
-
-
/**
-
* Write to stdout or stderr magically.
-
*
-
* @param string $method
-
* @param array $arguments
-
*
-
* @return self
-
*/
-
public function __call(string $method, array $arguments): self
-
{
-
if (method_exists($this->cursor, $method)) {
-
return $this->doWrite($this->cursor->{$method}(...$arguments));
-
}
-
-
$this->method = $method;
-
-
return $this->write(...$arguments);
-
}
-
}
-23
vendor/adhocore/cli/src/functions.php
···
-
<?php
-
-
/*
-
* This file is part of the PHP-CLI package.
-
*
-
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
-
* <https://github.com/adhocore>
-
*
-
* Licensed under MIT license.
-
*/
-
-
namespace Ahc\Cli;
-
-
/**
-
* Translates a message.
-
*/
-
function t(string $text, array $args = []): string
-
{
-
$translations = Application::$locales[Application::$locale] ?? [];
-
$text = $translations[$text] ?? $text;
-
-
return sprintf($text, ...$args);
-
}
-119
vendor/bin/runway
···
-
#!/usr/bin/env php
-
<?php
-
-
/**
-
* Proxy PHP file generated by Composer
-
*
-
* This file includes the referenced bin path (../flightphp/runway/runway)
-
* using a stream wrapper to prevent the shebang from being output on PHP<8
-
*
-
* @generated
-
*/
-
-
namespace Composer;
-
-
$GLOBALS['_composer_bin_dir'] = __DIR__;
-
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
-
-
if (PHP_VERSION_ID < 80000) {
-
if (!class_exists('Composer\BinProxyWrapper')) {
-
/**
-
* @internal
-
*/
-
final class BinProxyWrapper
-
{
-
private $handle;
-
private $position;
-
private $realpath;
-
-
public function stream_open($path, $mode, $options, &$opened_path)
-
{
-
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
-
$opened_path = substr($path, 17);
-
$this->realpath = realpath($opened_path) ?: $opened_path;
-
$opened_path = $this->realpath;
-
$this->handle = fopen($this->realpath, $mode);
-
$this->position = 0;
-
-
return (bool) $this->handle;
-
}
-
-
public function stream_read($count)
-
{
-
$data = fread($this->handle, $count);
-
-
if ($this->position === 0) {
-
$data = preg_replace('{^#!.*\r?\n}', '', $data);
-
}
-
-
$this->position += strlen($data);
-
-
return $data;
-
}
-
-
public function stream_cast($castAs)
-
{
-
return $this->handle;
-
}
-
-
public function stream_close()
-
{
-
fclose($this->handle);
-
}
-
-
public function stream_lock($operation)
-
{
-
return $operation ? flock($this->handle, $operation) : true;
-
}
-
-
public function stream_seek($offset, $whence)
-
{
-
if (0 === fseek($this->handle, $offset, $whence)) {
-
$this->position = ftell($this->handle);
-
return true;
-
}
-
-
return false;
-
}
-
-
public function stream_tell()
-
{
-
return $this->position;
-
}
-
-
public function stream_eof()
-
{
-
return feof($this->handle);
-
}
-
-
public function stream_stat()
-
{
-
return array();
-
}
-
-
public function stream_set_option($option, $arg1, $arg2)
-
{
-
return true;
-
}
-
-
public function url_stat($path, $flags)
-
{
-
$path = substr($path, 17);
-
if (file_exists($path)) {
-
return stat($path);
-
}
-
-
return false;
-
}
-
}
-
}
-
-
if (
-
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
-
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
-
) {
-
return include("phpvfscomposer://" . __DIR__ . '/..'.'/flightphp/runway/runway');
-
}
-
}
-
-
return include __DIR__ . '/..'.'/flightphp/runway/runway';
-41
vendor/composer/autoload_classmap.php
···
'Nette\\NotImplementedException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\NotSupportedException' => $vendorDir . '/nette/utils/src/exceptions.php',
'Nette\\OutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php',
-
'Nette\\PhpGenerator\\Attribute' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Attribute.php',
-
'Nette\\PhpGenerator\\ClassLike' => $vendorDir . '/nette/php-generator/src/PhpGenerator/ClassLike.php',
-
'Nette\\PhpGenerator\\ClassManipulator' => $vendorDir . '/nette/php-generator/src/PhpGenerator/ClassManipulator.php',
-
'Nette\\PhpGenerator\\ClassType' => $vendorDir . '/nette/php-generator/src/PhpGenerator/ClassType.php',
-
'Nette\\PhpGenerator\\Closure' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Closure.php',
-
'Nette\\PhpGenerator\\Constant' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Constant.php',
-
'Nette\\PhpGenerator\\Dumper' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Dumper.php',
-
'Nette\\PhpGenerator\\EnumCase' => $vendorDir . '/nette/php-generator/src/PhpGenerator/EnumCase.php',
-
'Nette\\PhpGenerator\\EnumType' => $vendorDir . '/nette/php-generator/src/PhpGenerator/EnumType.php',
-
'Nette\\PhpGenerator\\Extractor' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Extractor.php',
-
'Nette\\PhpGenerator\\Factory' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Factory.php',
-
'Nette\\PhpGenerator\\GlobalFunction' => $vendorDir . '/nette/php-generator/src/PhpGenerator/GlobalFunction.php',
-
'Nette\\PhpGenerator\\Helpers' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Helpers.php',
-
'Nette\\PhpGenerator\\InterfaceType' => $vendorDir . '/nette/php-generator/src/PhpGenerator/InterfaceType.php',
-
'Nette\\PhpGenerator\\Literal' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Literal.php',
-
'Nette\\PhpGenerator\\Method' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Method.php',
-
'Nette\\PhpGenerator\\Parameter' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Parameter.php',
-
'Nette\\PhpGenerator\\PhpFile' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PhpFile.php',
-
'Nette\\PhpGenerator\\PhpLiteral' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PhpLiteral.php',
-
'Nette\\PhpGenerator\\PhpNamespace' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PhpNamespace.php',
-
'Nette\\PhpGenerator\\Printer' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Printer.php',
-
'Nette\\PhpGenerator\\PromotedParameter' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PromotedParameter.php',
-
'Nette\\PhpGenerator\\Property' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Property.php',
-
'Nette\\PhpGenerator\\PropertyAccessMode' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PropertyAccessMode.php',
-
'Nette\\PhpGenerator\\PropertyHook' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PropertyHook.php',
-
'Nette\\PhpGenerator\\PropertyHookType' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PropertyHookType.php',
-
'Nette\\PhpGenerator\\PsrPrinter' => $vendorDir . '/nette/php-generator/src/PhpGenerator/PsrPrinter.php',
-
'Nette\\PhpGenerator\\TraitType' => $vendorDir . '/nette/php-generator/src/PhpGenerator/TraitType.php',
-
'Nette\\PhpGenerator\\TraitUse' => $vendorDir . '/nette/php-generator/src/PhpGenerator/TraitUse.php',
-
'Nette\\PhpGenerator\\Traits\\AttributeAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/AttributeAware.php',
-
'Nette\\PhpGenerator\\Traits\\CommentAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/CommentAware.php',
-
'Nette\\PhpGenerator\\Traits\\ConstantsAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/ConstantsAware.php',
-
'Nette\\PhpGenerator\\Traits\\FunctionLike' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/FunctionLike.php',
-
'Nette\\PhpGenerator\\Traits\\MethodsAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/MethodsAware.php',
-
'Nette\\PhpGenerator\\Traits\\NameAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/NameAware.php',
-
'Nette\\PhpGenerator\\Traits\\PropertiesAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/PropertiesAware.php',
-
'Nette\\PhpGenerator\\Traits\\PropertyLike' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/PropertyLike.php',
-
'Nette\\PhpGenerator\\Traits\\TraitsAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/TraitsAware.php',
-
'Nette\\PhpGenerator\\Traits\\VisibilityAware' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Traits/VisibilityAware.php',
-
'Nette\\PhpGenerator\\Type' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Type.php',
-
'Nette\\PhpGenerator\\Visibility' => $vendorDir . '/nette/php-generator/src/PhpGenerator/Visibility.php',
'Nette\\Schema\\Context' => $vendorDir . '/nette/schema/src/Schema/Context.php',
'Nette\\Schema\\DynamicParameter' => $vendorDir . '/nette/schema/src/Schema/DynamicParameter.php',
'Nette\\Schema\\Elements\\AnyOf' => $vendorDir . '/nette/schema/src/Schema/Elements/AnyOf.php',
-1
vendor/composer/autoload_files.php
···
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
-
'6594cffae477af99d531f0d3d4c9e533' => $vendorDir . '/adhocore/cli/src/functions.php',
'4cdafd4a5191caf078235e7dd119fdaf' => $vendorDir . '/flightphp/core/flight/autoload.php',
'ad155f8f1cf0d418fe49e248db8c661b' => $vendorDir . '/react/promise/src/functions_include.php',
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
+1 -3
vendor/composer/autoload_psr4.php
···
$baseDir = dirname($vendorDir);
return array(
-
'flight\\' => array($vendorDir . '/flightphp/runway/src'),
'chillerlan\\Utilities\\' => array($vendorDir . '/chillerlan/php-standard-utilities/src'),
'chillerlan\\Settings\\' => array($vendorDir . '/chillerlan/php-settings-container/src'),
'chillerlan\\OAuth\\' => array($vendorDir . '/chillerlan/php-oauth/src'),
···
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'),
-
'Nette\\' => array($vendorDir . '/nette/php-generator/src', $vendorDir . '/nette/utils/src'),
+
'Nette\\' => array($vendorDir . '/nette/utils/src'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'Masterminds\\' => array($vendorDir . '/masterminds/html5/src'),
'League\\Config\\' => array($vendorDir . '/league/config/src'),
···
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
'Fusonic\\OpenGraph\\' => array($vendorDir . '/fusonic/opengraph/src'),
'Dflydev\\DotAccessData\\' => array($vendorDir . '/dflydev/dot-access-data/src'),
-
'Ahc\\Cli\\' => array($vendorDir . '/adhocore/cli/src'),
);
+1 -60
vendor/composer/autoload_static.php
···
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
-
'6594cffae477af99d531f0d3d4c9e533' => __DIR__ . '/..' . '/adhocore/cli/src/functions.php',
'4cdafd4a5191caf078235e7dd119fdaf' => __DIR__ . '/..' . '/flightphp/core/flight/autoload.php',
'ad155f8f1cf0d418fe49e248db8c661b' => __DIR__ . '/..' . '/react/promise/src/functions_include.php',
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
···
);
public static $prefixLengthsPsr4 = array (
-
'f' =>
-
array (
-
'flight\\' => 7,
-
),
'c' =>
array (
'chillerlan\\Utilities\\' => 21,
···
array (
'Dflydev\\DotAccessData\\' => 22,
),
-
'A' =>
-
array (
-
'Ahc\\Cli\\' => 8,
-
),
);
public static $prefixDirsPsr4 = array (
-
'flight\\' =>
-
array (
-
0 => __DIR__ . '/..' . '/flightphp/runway/src',
-
),
'chillerlan\\Utilities\\' =>
array (
0 => __DIR__ . '/..' . '/chillerlan/php-standard-utilities/src',
···
),
'Nette\\' =>
array (
-
0 => __DIR__ . '/..' . '/nette/php-generator/src',
-
1 => __DIR__ . '/..' . '/nette/utils/src',
+
0 => __DIR__ . '/..' . '/nette/utils/src',
),
'Monolog\\' =>
array (
···
'Dflydev\\DotAccessData\\' =>
array (
0 => __DIR__ . '/..' . '/dflydev/dot-access-data/src',
-
),
-
'Ahc\\Cli\\' =>
-
array (
-
0 => __DIR__ . '/..' . '/adhocore/cli/src',
),
);
···
'Nette\\NotImplementedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\NotSupportedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
'Nette\\OutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php',
-
'Nette\\PhpGenerator\\Attribute' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Attribute.php',
-
'Nette\\PhpGenerator\\ClassLike' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/ClassLike.php',
-
'Nette\\PhpGenerator\\ClassManipulator' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/ClassManipulator.php',
-
'Nette\\PhpGenerator\\ClassType' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/ClassType.php',
-
'Nette\\PhpGenerator\\Closure' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Closure.php',
-
'Nette\\PhpGenerator\\Constant' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Constant.php',
-
'Nette\\PhpGenerator\\Dumper' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Dumper.php',
-
'Nette\\PhpGenerator\\EnumCase' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/EnumCase.php',
-
'Nette\\PhpGenerator\\EnumType' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/EnumType.php',
-
'Nette\\PhpGenerator\\Extractor' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Extractor.php',
-
'Nette\\PhpGenerator\\Factory' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Factory.php',
-
'Nette\\PhpGenerator\\GlobalFunction' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/GlobalFunction.php',
-
'Nette\\PhpGenerator\\Helpers' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Helpers.php',
-
'Nette\\PhpGenerator\\InterfaceType' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/InterfaceType.php',
-
'Nette\\PhpGenerator\\Literal' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Literal.php',
-
'Nette\\PhpGenerator\\Method' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Method.php',
-
'Nette\\PhpGenerator\\Parameter' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Parameter.php',
-
'Nette\\PhpGenerator\\PhpFile' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PhpFile.php',
-
'Nette\\PhpGenerator\\PhpLiteral' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PhpLiteral.php',
-
'Nette\\PhpGenerator\\PhpNamespace' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PhpNamespace.php',
-
'Nette\\PhpGenerator\\Printer' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Printer.php',
-
'Nette\\PhpGenerator\\PromotedParameter' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PromotedParameter.php',
-
'Nette\\PhpGenerator\\Property' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Property.php',
-
'Nette\\PhpGenerator\\PropertyAccessMode' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PropertyAccessMode.php',
-
'Nette\\PhpGenerator\\PropertyHook' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PropertyHook.php',
-
'Nette\\PhpGenerator\\PropertyHookType' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PropertyHookType.php',
-
'Nette\\PhpGenerator\\PsrPrinter' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/PsrPrinter.php',
-
'Nette\\PhpGenerator\\TraitType' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/TraitType.php',
-
'Nette\\PhpGenerator\\TraitUse' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/TraitUse.php',
-
'Nette\\PhpGenerator\\Traits\\AttributeAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/AttributeAware.php',
-
'Nette\\PhpGenerator\\Traits\\CommentAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/CommentAware.php',
-
'Nette\\PhpGenerator\\Traits\\ConstantsAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/ConstantsAware.php',
-
'Nette\\PhpGenerator\\Traits\\FunctionLike' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/FunctionLike.php',
-
'Nette\\PhpGenerator\\Traits\\MethodsAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/MethodsAware.php',
-
'Nette\\PhpGenerator\\Traits\\NameAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/NameAware.php',
-
'Nette\\PhpGenerator\\Traits\\PropertiesAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/PropertiesAware.php',
-
'Nette\\PhpGenerator\\Traits\\PropertyLike' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/PropertyLike.php',
-
'Nette\\PhpGenerator\\Traits\\TraitsAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/TraitsAware.php',
-
'Nette\\PhpGenerator\\Traits\\VisibilityAware' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Traits/VisibilityAware.php',
-
'Nette\\PhpGenerator\\Type' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Type.php',
-
'Nette\\PhpGenerator\\Visibility' => __DIR__ . '/..' . '/nette/php-generator/src/PhpGenerator/Visibility.php',
'Nette\\Schema\\Context' => __DIR__ . '/..' . '/nette/schema/src/Schema/Context.php',
'Nette\\Schema\\DynamicParameter' => __DIR__ . '/..' . '/nette/schema/src/Schema/DynamicParameter.php',
'Nette\\Schema\\Elements\\AnyOf' => __DIR__ . '/..' . '/nette/schema/src/Schema/Elements/AnyOf.php',
+2 -207
vendor/composer/installed.json
···
{
"packages": [
{
-
"name": "adhocore/cli",
-
"version": "v1.9.4",
-
"version_normalized": "1.9.4.0",
-
"source": {
-
"type": "git",
-
"url": "https://github.com/adhocore/php-cli.git",
-
"reference": "474dc3d7ab139796be98b104d891476e3916b6f4"
-
},
-
"dist": {
-
"type": "zip",
-
"url": "https://api.github.com/repos/adhocore/php-cli/zipball/474dc3d7ab139796be98b104d891476e3916b6f4",
-
"reference": "474dc3d7ab139796be98b104d891476e3916b6f4",
-
"shasum": ""
-
},
-
"require": {
-
"php": ">=8.0"
-
},
-
"require-dev": {
-
"phpunit/phpunit": "^9.0"
-
},
-
"time": "2025-05-11T13:23:54+00:00",
-
"type": "library",
-
"installation-source": "dist",
-
"autoload": {
-
"files": [
-
"src/functions.php"
-
],
-
"psr-4": {
-
"Ahc\\Cli\\": "src/"
-
}
-
},
-
"notification-url": "https://packagist.org/downloads/",
-
"license": [
-
"MIT"
-
],
-
"authors": [
-
{
-
"name": "Jitendra Adhikari",
-
"email": "jiten.adhikary@gmail.com"
-
}
-
],
-
"description": "Command line interface library for PHP",
-
"keywords": [
-
"argument-parser",
-
"argv-parser",
-
"cli",
-
"cli-action",
-
"cli-app",
-
"cli-color",
-
"cli-option",
-
"cli-writer",
-
"command",
-
"console",
-
"console-app",
-
"php-cli",
-
"php8",
-
"stream-input",
-
"stream-output"
-
],
-
"support": {
-
"issues": "https://github.com/adhocore/php-cli/issues",
-
"source": "https://github.com/adhocore/php-cli/tree/v1.9.4"
-
},
-
"funding": [
-
{
-
"url": "https://paypal.me/ji10",
-
"type": "custom"
-
},
-
{
-
"url": "https://github.com/adhocore",
-
"type": "github"
-
}
-
],
-
"install-path": "../adhocore/cli"
-
},
-
{
"name": "chillerlan/php-http-message-utils",
"version": "2.2.2",
"version_normalized": "2.2.2.0",
···
"install-path": "../flightphp/core"
},
{
-
"name": "flightphp/runway",
-
"version": "v1.1.2",
-
"version_normalized": "1.1.2.0",
-
"source": {
-
"type": "git",
-
"url": "https://github.com/flightphp/runway.git",
-
"reference": "b88c1901b77eda935ef475af772445c3108cf23f"
-
},
-
"dist": {
-
"type": "zip",
-
"url": "https://api.github.com/repos/flightphp/runway/zipball/b88c1901b77eda935ef475af772445c3108cf23f",
-
"reference": "b88c1901b77eda935ef475af772445c3108cf23f",
-
"shasum": ""
-
},
-
"require": {
-
"adhocore/cli": "^1.7",
-
"nette/php-generator": "^4.1",
-
"php": "^8.2"
-
},
-
"require-dev": {
-
"phpstan/extension-installer": "^1.3",
-
"phpstan/phpstan": "^1.10",
-
"phpunit/phpunit": "^9.5",
-
"rregeer/phpunit-coverage-check": "^0.3.1",
-
"squizlabs/php_codesniffer": "^3.8"
-
},
-
"time": "2025-01-11T17:52:47+00:00",
-
"bin": [
-
"runway"
-
],
-
"type": "library",
-
"installation-source": "dist",
-
"autoload": {
-
"psr-4": {
-
"flight\\": "src/"
-
}
-
},
-
"notification-url": "https://packagist.org/downloads/",
-
"license": [
-
"MIT"
-
],
-
"authors": [
-
{
-
"name": "n0nag0n",
-
"email": "n0nag0n@sky-9.com"
-
}
-
],
-
"description": "Console app for the Flight PHP Framework.",
-
"support": {
-
"issues": "https://github.com/flightphp/runway/issues",
-
"source": "https://github.com/flightphp/runway/tree/v1.1.2"
-
},
-
"install-path": "../flightphp/runway"
-
},
-
{
"name": "flightphp/tracy-extensions",
"version": "v0.2.7",
"version_normalized": "0.2.7.0",
···
],
"install-path": "../monolog/monolog"
-
},
-
{
-
"name": "nette/php-generator",
-
"version": "v4.2.0",
-
"version_normalized": "4.2.0.0",
-
"source": {
-
"type": "git",
-
"url": "https://github.com/nette/php-generator.git",
-
"reference": "4707546a1f11badd72f5d82af4f8a6bc64bd56ac"
-
},
-
"dist": {
-
"type": "zip",
-
"url": "https://api.github.com/repos/nette/php-generator/zipball/4707546a1f11badd72f5d82af4f8a6bc64bd56ac",
-
"reference": "4707546a1f11badd72f5d82af4f8a6bc64bd56ac",
-
"shasum": ""
-
},
-
"require": {
-
"nette/utils": "^4.0.6",
-
"php": "8.1 - 8.5"
-
},
-
"require-dev": {
-
"jetbrains/phpstorm-attributes": "^1.2",
-
"nette/tester": "^2.4",
-
"nikic/php-parser": "^5.0",
-
"phpstan/phpstan-nette": "^2.0@stable",
-
"tracy/tracy": "^2.8"
-
},
-
"suggest": {
-
"nikic/php-parser": "to use ClassType::from(withBodies: true) & ClassType::fromCode()"
-
},
-
"time": "2025-08-06T18:24:31+00:00",
-
"type": "library",
-
"extra": {
-
"branch-alias": {
-
"dev-master": "4.2-dev"
-
}
-
},
-
"installation-source": "dist",
-
"autoload": {
-
"psr-4": {
-
"Nette\\": "src"
-
},
-
"classmap": [
-
"src/"
-
]
-
},
-
"notification-url": "https://packagist.org/downloads/",
-
"license": [
-
"BSD-3-Clause",
-
"GPL-2.0-only",
-
"GPL-3.0-only"
-
],
-
"authors": [
-
{
-
"name": "David Grudl",
-
"homepage": "https://davidgrudl.com"
-
},
-
{
-
"name": "Nette Community",
-
"homepage": "https://nette.org/contributors"
-
}
-
],
-
"description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.5 features.",
-
"homepage": "https://nette.org",
-
"keywords": [
-
"code",
-
"nette",
-
"php",
-
"scaffolding"
-
],
-
"support": {
-
"issues": "https://github.com/nette/php-generator/issues",
-
"source": "https://github.com/nette/php-generator/tree/v4.2.0"
-
},
-
"install-path": "../nette/php-generator"
},
"name": "nette/schema",
···
],
"dev": true,
"dev-package-names": [
-
"flightphp/tracy-extensions"
+
"flightphp/tracy-extensions",
+
"tracy/tracy"
+3 -30
vendor/composer/installed.php
···
'name' => '__root__',
'pretty_version' => 'dev-main',
'version' => 'dev-main',
-
'reference' => 'bea8476a6fd638d67046c875c6410c586ef4f117',
+
'reference' => 'fdbf1c1dbbcba6761225da71521619f9ac0df6de',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
···
'__root__' => array(
'pretty_version' => 'dev-main',
'version' => 'dev-main',
-
'reference' => 'bea8476a6fd638d67046c875c6410c586ef4f117',
+
'reference' => 'fdbf1c1dbbcba6761225da71521619f9ac0df6de',
'type' => 'library',
'install_path' => __DIR__ . '/../../',
-
'aliases' => array(),
-
'dev_requirement' => false,
-
),
-
'adhocore/cli' => array(
-
'pretty_version' => 'v1.9.4',
-
'version' => '1.9.4.0',
-
'reference' => '474dc3d7ab139796be98b104d891476e3916b6f4',
-
'type' => 'library',
-
'install_path' => __DIR__ . '/../adhocore/cli',
'aliases' => array(),
'dev_requirement' => false,
),
···
'aliases' => array(),
'dev_requirement' => false,
),
-
'flightphp/runway' => array(
-
'pretty_version' => 'v1.1.2',
-
'version' => '1.1.2.0',
-
'reference' => 'b88c1901b77eda935ef475af772445c3108cf23f',
-
'type' => 'library',
-
'install_path' => __DIR__ . '/../flightphp/runway',
-
'aliases' => array(),
-
'dev_requirement' => false,
-
),
'flightphp/tracy-extensions' => array(
'pretty_version' => 'v0.2.7',
'version' => '0.2.7.0',
···
'reference' => '10d85740180ecba7896c87e06a166e0c95a0e3b6',
'type' => 'library',
'install_path' => __DIR__ . '/../monolog/monolog',
-
'aliases' => array(),
-
'dev_requirement' => false,
-
),
-
'nette/php-generator' => array(
-
'pretty_version' => 'v4.2.0',
-
'version' => '4.2.0.0',
-
'reference' => '4707546a1f11badd72f5d82af4f8a6bc64bd56ac',
-
'type' => 'library',
-
'install_path' => __DIR__ . '/../nette/php-generator',
'aliases' => array(),
'dev_requirement' => false,
),
···
'type' => 'library',
'install_path' => __DIR__ . '/../tracy/tracy',
'aliases' => array(),
-
'dev_requirement' => false,
+
'dev_requirement' => true,
),
),
);
-9
vendor/flightphp/runway/.gitignore
···
-
.idea
-
vendor/
-
composer.phar
-
composer.lock
-
.phpunit.result.cache
-
coverage/
-
*.sublime*
-
clover.xml
-
.runway-config.json
-3
vendor/flightphp/runway/.vscode/settings.json
···
-
{
-
"php.suggest.basic": false
-
}
-21
vendor/flightphp/runway/LICENSE
···
-
MIT License
-
-
Copyright (c) 2024 n0nag0n <n0nag0n@sky-9.com>
-
-
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.
-31
vendor/flightphp/runway/README.md
···
-
# What is Runway?
-
-
Runway is a console app for managing your Flight projects. This is built off the backbone of the amazing [adhocore/php-cli](https://github.com/adhocore/php-cli) libraries.
-
-
> v1.0 requires PHP 8.2+. For PHP 7.4, 8.0, and 8.1 use version 0.2.3 and forward.
-
-
# Basic Usage
-
-
```bash
-
vendor/bin/runway --help
-
```
-
-
This will show you all the possible commands you can run with Runway.
-
-
You can see the options for each of the commands by adding `--help` or `-h` to the command.
-
-
```bash
-
vendor/bin/runway routes --help
-
```
-
-
# Installation
-
-
Installation is done through composer.
-
-
```bash
-
composer require flightphp/runway
-
```
-
-
# License
-
-
Flight Runway is released under the [MIT](http://docs.flightphp.com/license) license.
-47
vendor/flightphp/runway/composer.json
···
-
{
-
"name": "flightphp/runway",
-
"description": "Console app for the Flight PHP Framework.",
-
"type": "library",
-
"license": "MIT",
-
"autoload": {
-
"psr-4": {
-
"flight\\": "src/"
-
}
-
},
-
"authors": [
-
{
-
"name": "n0nag0n",
-
"email": "n0nag0n@sky-9.com"
-
}
-
],
-
"require-dev": {
-
"phpstan/extension-installer": "^1.3",
-
"phpstan/phpstan": "^1.10",
-
"phpunit/phpunit": "^9.5",
-
"rregeer/phpunit-coverage-check": "^0.3.1",
-
"squizlabs/php_codesniffer": "^3.8"
-
},
-
"scripts": {
-
"test": "phpunit",
-
"test-coverage": "rm -f clover.xml && XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-html=coverage --coverage-clover=clover.xml && vendor/bin/coverage-check clover.xml 100",
-
"lint": "phpstan --no-progress -cphpstan.neon",
-
"beautify": "phpcbf --standard=phpcs.xml",
-
"phpcs": "phpcs --standard=phpcs.xml -n",
-
"post-install-cmd": [
-
"php -r \"if (!file_exists('phpcs.xml')) copy('phpcs.xml.dist', 'phpcs.xml');\""
-
]
-
},
-
"bin": [
-
"runway"
-
],
-
"config": {
-
"allow-plugins": {
-
"phpstan/extension-installer": true
-
}
-
},
-
"require": {
-
"php": "^8.2",
-
"adhocore/cli": "^1.7",
-
"nette/php-generator": "^4.1"
-
}
-
}
-52
vendor/flightphp/runway/phpcs.xml
···
-
<?xml version="1.0" encoding="UTF-8"?>
-
<ruleset
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:noNamespaceSchemaLocation="./vendor/squizlabs/php_codesniffer/phpcs.xsd"
-
name="pcsg-generated-ruleset">
-
<description>
-
Created with the PHP Coding Standard Generator.
-
http://edorian.github.io/php-coding-standard-generator/
-
</description>
-
<arg name="colors" />
-
<arg name="tab-width" value="4" />
-
<rule ref="PSR1">
-
<exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace" />
-
</rule>
-
<rule ref="PSR12" />
-
<rule ref="Generic">
-
<exclude name="Generic.PHP.ClosingPHPTag.NotFound" />
-
<exclude name="Generic.PHP.UpperCaseConstant.Found" />
-
<exclude name="Generic.Arrays.DisallowShortArraySyntax.Found" />
-
<exclude name="Generic.Files.EndFileNoNewline.Found" />
-
<exclude name="Generic.Files.LowercasedFilename.NotFound" />
-
<exclude name="Generic.Commenting.DocComment.TagValueIndent" />
-
<exclude name="Generic.Classes.OpeningBraceSameLine.BraceOnNewLine" />
-
<exclude name="Generic.WhiteSpace.DisallowSpaceIndent.SpacesUsed" />
-
<exclude name="Generic.Commenting.DocComment.ContentAfterOpen" />
-
<exclude name="Generic.Commenting.DocComment.ContentBeforeClose" />
-
<exclude name="Generic.Commenting.DocComment.MissingShort" />
-
<exclude name="Generic.Commenting.DocComment.SpacingBeforeShort" />
-
<exclude name="Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine" />
-
<exclude name="Generic.Formatting.MultipleStatementAlignment.NotSameWarning" />
-
<exclude name="Generic.Functions.OpeningFunctionBraceBsdAllman.BraceOnSameLine" />
-
<exclude name="Generic.PHP.DisallowRequestSuperglobal.Found" />
-
</rule>
-
<rule ref="Generic.Files.LineLength">
-
<properties>
-
<property name="ignoreComments" value="true" />
-
</properties>
-
</rule>
-
<rule ref="Generic.Formatting.SpaceAfterNot">
-
<properties>
-
<property name="spacing" value="0" />
-
</properties>
-
</rule>
-
<rule ref="Generic.WhiteSpace.ArbitraryParenthesesSpacing">
-
<properties>
-
<property name="ignoreNewlines" value="true" />
-
</properties>
-
</rule>
-
<file>src/</file>
-
<file>tests/</file>
-
<file>scripts/</file>
-
</ruleset>
-7
vendor/flightphp/runway/phpstan.neon
···
-
parameters:
-
level: 6
-
excludePaths:
-
- vendor
-
paths:
-
- src
-
treatPhpDocTypesAsCertain: false
-29
vendor/flightphp/runway/phpunit.xml
···
-
<?xml version="1.0" encoding="UTF-8"?>
-
<phpunit
-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
-
bootstrap="vendor/autoload.php"
-
executionOrder="random"
-
beStrictAboutOutputDuringTests="true"
-
beStrictAboutTodoAnnotatedTests="true"
-
convertDeprecationsToExceptions="true"
-
stopOnError="true"
-
stopOnFailure="true"
-
verbose="true"
-
colors="true">
-
<coverage processUncoveredFiles="true">
-
<include>
-
<directory suffix=".php">flight/</directory>
-
</include>
-
</coverage>
-
<testsuites>
-
<testsuite name="default">
-
<directory>tests/</directory>
-
</testsuite>
-
</testsuites>
-
<logging />
-
<php>
-
<ini name="error_reporting" value="-1"/>
-
<env name="PHPUNIT_TEST" value="true" force="true" />
-
</php>
-
</phpunit>
-116
vendor/flightphp/runway/runway
···
-
#!/usr/bin/env php
-
<?php
-
-
foreach ([ __DIR__ . '/../../autoload.php', __DIR__ . '/../vendor/autoload.php', __DIR__ . '/vendor/autoload.php' ] as $file) {
-
if (file_exists($file) === true) {
-
require($file);
-
break;
-
}
-
}
-
-
$cwd = getcwd();
-
// Config this bad boy.
-
if(file_exists($cwd.'/.runway-config.json') === false) {
-
return require __DIR__.'/scripts/setup.php';
-
}
-
-
$config = json_decode(file_get_contents($cwd.'/.runway-config.json'), true);
-
-
$consoleApp = new Ahc\Cli\Application('runway', '1.1.2');
-
-
$cwd = getcwd();
-
-
// root paths are the paths to get to the root of a project
-
$rootPaths = [
-
$cwd,
-
__DIR__
-
];
-
-
if(isset($config['root_paths'])) {
-
$rootPaths = array_merge($rootPaths, $config['root_paths']);
-
}
-
-
// base paths are paths to get to the base directory of subprojectsprojects.
-
$basePaths = [
-
'', // to capture commands in the root of the project
-
'/**', // capture random packages
-
'/**/**', // capture more randomness
-
'/**/**/**', // this is getting fun now
-
'/**/**/**/**', // yee-freakin'-haw!
-
];
-
-
if(isset($config['base_paths'])) {
-
$basePaths = array_merge($basePaths, $config['base_paths']);
-
}
-
-
// Final paths are the final directories where it's expecting to find commands
-
$finalPaths = [
-
'/src/commands/*.php',
-
'/flight/commands/*.php',
-
'/commands/*.php',
-
];
-
-
// Add the app root if you decided to configure it
-
if(isset($config['app_root']) === true) {
-
$finalPaths[] = '/'.$config['app_root'].'commands/*.php';
-
}
-
-
if(isset($config['final_paths'])) {
-
$finalPaths = array_merge($finalPaths, $config['final_paths']);
-
}
-
-
// Now that we've figured out all the possible paths, let's do this!
-
foreach($rootPaths as $rootPath) {
-
foreach($basePaths as $basePath) {
-
foreach($finalPaths as $finalPath) {
-
$paths[] = $rootPath.$basePath.$finalPath;
-
}
-
}
-
}
-
-
// These are paths to check for commands
-
if(isset($config['paths'])) {
-
$paths = array_merge($paths, $config['paths']);
-
}
-
-
$addedCommands = [];
-
foreach($paths as $path) {
-
foreach(glob($path) as $commandPath) {
-
-
$baseName = basename($commandPath);
-
-
// Ignore the AbstractBaseCommand class and any *CommandTest.php files
-
if($baseName === 'AbstractBaseCommand.php' || strpos($baseName, 'CommandTest.php') !== false) {
-
continue;
-
}
-
$command = str_replace('.php', '', $baseName);
-
-
// pull the namespace from the contents of the file
-
$contents = file_get_contents($commandPath);
-
preg_match('/namespace (.*);/', $contents, $matches);
-
$namespace = $matches[1];
-
$command = $namespace.'\\'.$command;
-
-
// To prevent duplicates from being loaded
-
if(in_array($command, $addedCommands, true) === true) {
-
continue;
-
}
-
// Keep track of the commands added
-
$addedCommands[] = $command;
-
-
// Get the code
-
require $commandPath;
-
-
// Ignore classes extending TestCase
-
if(is_subclass_of($command, PHPUnit\Framework\TestCase::class)) {
-
continue;
-
}
-
-
// Add the command
-
$consoleApp->add(new $command($config));
-
}
-
}
-
-
$argv = (array) $_SERVER['argv'];
-
-
$consoleApp->handle($argv);
-45
vendor/flightphp/runway/scripts/setup.php
···
-
<?php
-
-
declare(strict_types=1);
-
-
$interactor = new Ahc\Cli\IO\Interactor();
-
-
$interactor->boldBlue('Welcome to the Runway setup wizard!', true);
-
$interactor->blue('This wizard will help you get your settings correct for your Flight project.', true);
-
-
// Main index.php file
-
$possible_file_locations = [
-
'1' => 'public/index.php',
-
'2' => 'index.php',
-
'3' => 'web/index.php',
-
'4' => 'www/index.php',
-
'5' => 'other'
-
];
-
$choice = $interactor->choice('Where is your root index.php file located for your project?', $possible_file_locations, '1');
-
if ($choice === '5') {
-
$index_location = $interactor->prompt('Please enter the path to your root index.php file: ');
-
} else {
-
$index_location = $possible_file_locations[$choice];
-
}
-
-
// Core app directory
-
$possible_app_locations = [
-
'1' => 'app/',
-
'2' => 'lib/',
-
'3' => './',
-
'4' => 'other'
-
];
-
$choice = $interactor->choice('Where is your root app directory where you store all your controllers, views, utility classes, etc?', $possible_app_locations, '1');
-
if ($choice === '4') {
-
$app_location = $interactor->prompt('Please enter the path to your root app directory: ');
-
} else {
-
$app_location = $possible_app_locations[$choice];
-
}
-
-
$json = json_encode([
-
'index_root' => $index_location,
-
'app_root' => $app_location
-
], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
-
-
$interactor->boldGreen('Your settings have been saved!', true);
-
file_put_contents(getcwd() . '/.runway-config.json', $json);
-24
vendor/flightphp/runway/src/commands/AbstractBaseCommand.php
···
-
<?php
-
-
declare(strict_types=1);
-
-
namespace flight\commands;
-
-
abstract class AbstractBaseCommand extends \Ahc\Cli\Input\Command
-
{
-
/** @var array<string,mixed> */
-
protected array $config;
-
-
/**
-
* Construct
-
*
-
* @param string $name Good ol' name
-
* @param string $description Good ol' description
-
* @param array<string,mixed> $config config from .runway-config.json
-
*/
-
public function __construct(string $name, string $description, array $config)
-
{
-
parent::__construct($name, $description);
-
$this->config = $config;
-
}
-
}
-47
vendor/nette/php-generator/composer.json
···
-
{
-
"name": "nette/php-generator",
-
"description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 8.5 features.",
-
"keywords": ["nette", "php", "code", "scaffolding"],
-
"homepage": "https://nette.org",
-
"license": ["BSD-3-Clause", "GPL-2.0-only", "GPL-3.0-only"],
-
"authors": [
-
{
-
"name": "David Grudl",
-
"homepage": "https://davidgrudl.com"
-
},
-
{
-
"name": "Nette Community",
-
"homepage": "https://nette.org/contributors"
-
}
-
],
-
"require": {
-
"php": "8.1 - 8.5",
-
"nette/utils": "^4.0.6"
-
},
-
"require-dev": {
-
"nette/tester": "^2.4",
-
"nikic/php-parser": "^5.0",
-
"tracy/tracy": "^2.8",
-
"phpstan/phpstan-nette": "^2.0@stable",
-
"jetbrains/phpstorm-attributes": "^1.2"
-
},
-
"suggest": {
-
"nikic/php-parser": "to use ClassType::from(withBodies: true) & ClassType::fromCode()"
-
},
-
"autoload": {
-
"classmap": ["src/"],
-
"psr-4": {
-
"Nette\\": "src"
-
}
-
},
-
"minimum-stability": "dev",
-
"scripts": {
-
"phpstan": "phpstan analyse",
-
"tester": "tester tests -s"
-
},
-
"extra": {
-
"branch-alias": {
-
"dev-master": "4.2-dev"
-
}
-
}
-
}
-60
vendor/nette/php-generator/license.md
···
-
Licenses
-
========
-
-
Good news! You may use Nette Framework under the terms of either
-
the New BSD License or the GNU General Public License (GPL) version 2 or 3.
-
-
The BSD License is recommended for most projects. It is easy to understand and it
-
places almost no restrictions on what you can do with the framework. If the GPL
-
fits better to your project, you can use the framework under this license.
-
-
You don't have to notify anyone which license you are using. You can freely
-
use Nette Framework in commercial projects as long as the copyright header
-
remains intact.
-
-
Please be advised that the name "Nette Framework" is a protected trademark and its
-
usage has some limitations. So please do not use word "Nette" in the name of your
-
project or top-level domain, and choose a name that stands on its own merits.
-
If your stuff is good, it will not take long to establish a reputation for yourselves.
-
-
-
New BSD License
-
---------------
-
-
Copyright (c) 2004, 2014 David Grudl (https://davidgrudl.com)
-
All 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.
-
-
* Neither the name of "Nette Framework" nor the names of its contributors
-
may 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.
-
-
-
GNU General Public License
-
--------------------------
-
-
GPL licenses are very very long, so instead of including them here we offer
-
you URLs with full text:
-
-
- [GPL version 2](http://www.gnu.org/licenses/gpl-2.0.html)
-
- [GPL version 3](http://www.gnu.org/licenses/gpl-3.0.html)
-1008
vendor/nette/php-generator/readme.md
···
-
[![Nette PHP Generator](https://github.com/nette/php-generator/assets/194960/8a2c83bd-daea-475f-994c-9c951de88501)](https://doc.nette.org/en/php-generator)
-
-
[![Latest Stable Version](https://poser.pugx.org/nette/php-generator/v/stable)](https://github.com/nette/php-generator/releases) [![Downloads this Month](https://img.shields.io/packagist/dm/nette/php-generator.svg)](https://packagist.org/packages/nette/php-generator)
-
-
 <!---->
-
-
Are you looking for a tool to generate PHP code for [classes](#classes), [functions](#global-functions), or complete [PHP files](#php-files)?
-
-
<h3>
-
-
✅ Supports all the latest PHP features like [property hooks](#property-hooks), [enums](#enums), [attributes](#attributes), etc.<br>
-
✅ Allows you to easily modify [existing classes](#generating-from-existing-ones)<br>
-
✅ Output compliant with [PSR-12 / PER coding style](#printer-and-psr-compliance)<br>
-
✅ Highly mature, stable, and widely used library
-
-
</h3>
-
-
 <!---->
-
-
Installation
-
------------
-
-
Download and install the library using the [Composer](https://doc.nette.org/en/best-practices/composer) tool:
-
-
```shell
-
composer require nette/php-generator
-
```
-
-
PhpGenerator 4.2 is compatible with PHP 8.1 to 8.5. Documentation can be found on the [library's website](https://doc.nette.org/php-generator).
-
-
 <!---->
-
-
[Support Me](https://github.com/sponsors/dg)
-
--------------------------------------------
-
-
Do you like PHP Generator? Are you looking forward to the new features?
-
-
[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg)
-
-
Thank you!
-
-
 <!---->
-
-
Classes
-
-------
-
-
Let's start with an example of creating a class using [ClassType](https://api.nette.org/php-generator/master/Nette/PhpGenerator/ClassType.html):
-
-
```php
-
$class = new Nette\PhpGenerator\ClassType('Demo');
-
-
$class
-
->setFinal()
-
->setExtends(ParentClass::class)
-
->addImplement(Countable::class)
-
->addComment("Class description.\nSecond line\n")
-
->addComment('@property-read Nette\Forms\Form $form');
-
-
// generate code simply by typecasting to string or using echo:
-
echo $class;
-
```
-
-
This will return:
-
-
```php
-
/**
-
* Class description
-
* Second line
-
*
-
* @property-read Nette\Forms\Form $form
-
*/
-
final class Demo extends ParentClass implements Countable
-
{
-
}
-
```
-
-
To generate the code, you can also use a so-called printer, which, unlike `echo $class`, can be [further configured](#printer-and-psr-compliance):
-
-
```php
-
$printer = new Nette\PhpGenerator\Printer;
-
echo $printer->printClass($class);
-
```
-
-
You can add constants (class [Constant](https://api.nette.org/php-generator/master/Nette/PhpGenerator/Constant.html)) and properties (class [Property](https://api.nette.org/php-generator/master/Nette/PhpGenerator/Property.html)):
-
-
```php
-
$class->addConstant('ID', 123)
-
->setProtected() // constant visibility
-
->setType('int')
-
->setFinal();
-
-
$class->addProperty('items', [1, 2, 3])
-
->setPrivate() // or setVisibility('private')
-
->setStatic()
-
->addComment('@var int[]');
-
-
$class->addProperty('list')
-
->setType('?array')
-
->setInitialized(); // outputs '= null'
-
```
-
-
This will generate:
-
-
```php
-
final protected const int ID = 123;
-
-
/** @var int[] */
-
private static $items = [1, 2, 3];
-
-
public ?array $list = null;
-
```
-
-
And you can add [methods](#method-and-function-signatures):
-
-
```php
-
$method = $class->addMethod('count')
-
->addComment('Count it.')
-
->setFinal()
-
->setProtected()
-
->setReturnType('?int') // return types for methods
-
->setBody('return count($items ?: $this->items);');
-
-
$method->addParameter('items', []) // $items = []
-
->setReference() // &$items = []
-
->setType('array'); // array &$items = []
-
```
-
-
The result is:
-
-
```php
-
/**
-
* Count it.
-
*/
-
final protected function count(array &$items = []): ?int
-
{
-
return count($items ?: $this->items);
-
}
-
```
-
-
Promoted parameters introduced in PHP 8.0 can be passed to the constructor:
-
-
```php
-
$method = $class->addMethod('__construct');
-
$method->addPromotedParameter('name');
-
$method->addPromotedParameter('args', [])
-
->setPrivate();
-
```
-
-
The result is:
-
-
```php
-
public function __construct(
-
public $name,
-
private $args = [],
-
) {
-
}
-
```
-
-
Readonly properties and classes be marked using the `setReadOnly()` function.
-
-
------
-
-
If an added property, constant, method, or parameter already exists, an exception is thrown.
-
-
Class members can be removed using `removeProperty()`, `removeConstant()`, `removeMethod()`, or `removeParameter()`.
-
-
You can also add existing `Method`, `Property`, or `Constant` objects to the class:
-
-
```php
-
$method = new Nette\PhpGenerator\Method('getHandle');
-
$property = new Nette\PhpGenerator\Property('handle');
-
$const = new Nette\PhpGenerator\Constant('ROLE');
-
-
$class = (new Nette\PhpGenerator\ClassType('Demo'))
-
->addMember($method)
-
->addMember($property)
-
->addMember($const);
-
```
-
-
You can also clone existing methods, properties, and constants under a different name using `cloneWithName()`:
-
-
```php
-
$methodCount = $class->getMethod('count');
-
$methodRecount = $methodCount->cloneWithName('recount');
-
$class->addMember($methodRecount);
-
```
-
-
 <!---->
-
-
Interfaces or Traits
-
--------------------
-
-
You can create interfaces and traits (classes [InterfaceType](https://api.nette.org/php-generator/master/Nette/PhpGenerator/InterfaceType.html) and [TraitType](https://api.nette.org/php-generator/master/Nette/PhpGenerator/TraitType.html)):
-
-
```php
-
$interface = new Nette\PhpGenerator\InterfaceType('MyInterface');
-
$trait = new Nette\PhpGenerator\TraitType('MyTrait');
-
```
-
-
Using a trait:
-
-
```php
-
$class = new Nette\PhpGenerator\ClassType('Demo');
-
$class->addTrait('SmartObject');
-
$class->addTrait('MyTrait')
-
->addResolution('sayHello as protected')
-
->addComment('@use MyTrait<Foo>');
-
echo $class;
-
```
-
-
The result is:
-
-
```php
-
class Demo
-
{
-
use SmartObject;
-
/** @use MyTrait<Foo> */
-
use MyTrait {
-
sayHello as protected;
-
}
-
}
-
```
-
-
 <!---->
-
-
Enums
-
-----
-
-
You can easily create enums introduced in PHP 8.1 like this (class [EnumType](https://api.nette.org/php-generator/master/Nette/PhpGenerator/EnumType.html)):
-
-
```php
-
$enum = new Nette\PhpGenerator\EnumType('Suit');
-
$enum->addCase('Clubs');
-
$enum->addCase('Diamonds');
-
$enum->addCase('Hearts');
-
$enum->addCase('Spades');
-
-
echo $enum;
-
```
-
-
The result is:
-
-
```php
-
enum Suit
-
{
-
case Clubs;
-
case Diamonds;
-
case Hearts;
-
case Spades;
-
}
-
```
-
-
You can also define scalar equivalents and create a "backed" enum:
-
-
```php
-
$enum->addCase('Clubs', '♣');
-
$enum->addCase('Diamonds', '♦');
-
```
-
-
For each *case*, you can add a comment or [attributes](#attributes) using `addComment()` or `addAttribute()`.
-
-
 <!---->
-
-
Anonymous Classes
-
-----------------
-
-
Pass `null` as the name, and you have an anonymous class:
-
-
```php
-
$class = new Nette\PhpGenerator\ClassType(null);
-
$class->addMethod('__construct')
-
->addParameter('foo');
-
-
echo '$obj = new class ($val) ' . $class . ';';
-
```
-
-
The result is:
-
-
```php
-
$obj = new class ($val) {
-
-
public function __construct($foo)
-
{
-
}
-
};
-
```
-
-
 <!---->
-
-
Global Functions
-
----------------
-
-
The code for functions is generated by the class [GlobalFunction](https://api.nette.org/php-generator/master/Nette/PhpGenerator/GlobalFunction.html):
-
-
```php
-
$function = new Nette\PhpGenerator\GlobalFunction('foo');
-
$function->setBody('return $a + $b;');
-
$function->addParameter('a');
-
$function->addParameter('b');
-
echo $function;
-
-
// or use the PsrPrinter for output compliant with PSR-2 / PSR-12 / PER
-
// echo (new Nette\PhpGenerator\PsrPrinter)->printFunction($function);
-
```
-
-
The result is:
-
-
```php
-
function foo($a, $b)
-
{
-
return $a + $b;
-
}
-
```
-
-
 <!---->
-
-
Anonymous Functions
-
-------------------
-
-
The code for anonymous functions is generated by the class [Closure](https://api.nette.org/php-generator/master/Nette/PhpGenerator/Closure.html):
-
-
```php
-
$closure = new Nette\PhpGenerator\Closure;
-
$closure->setBody('return $a + $b;');
-
$closure->addParameter('a');
-
$closure->addParameter('b');
-
$closure->addUse('c')
-
->setReference();
-
echo $closure;
-
-
// or use the PsrPrinter for output compliant with PSR-2 / PSR-12 / PER
-
// echo (new Nette\PhpGenerator\PsrPrinter)->printClosure($closure);
-
```
-
-
The result is:
-
-
```php
-
function ($a, $b) use (&$c) {
-
return $a + $b;
-
}
-
```
-
-
 <!---->
-
-
Short Arrow Functions
-
---------------------
-
-
You can also output a short anonymous function using the printer:
-
-
```php
-
$closure = new Nette\PhpGenerator\Closure;
-
$closure->setBody('$a + $b');
-
$closure->addParameter('a');
-
$closure->addParameter('b');
-
-
echo (new Nette\PhpGenerator\Printer)->printArrowFunction($closure);
-
```
-
-
The result is:
-
-
```php
-
fn($a, $b) => $a + $b
-
```
-
-
 <!---->
-
-
Method and Function Signatures
-
------------------------------
-
-
Methods are represented by the class [Method](https://api.nette.org/php-generator/master/Nette/PhpGenerator/Method.html). You can set visibility, return value, add comments, [attributes](#attributes), etc.:
-
-
```php
-
$method = $class->addMethod('count')
-
->addComment('Count it.')
-
->setFinal()
-
->setProtected()
-
->setReturnType('?int');
-
```
-
-
Individual parameters are represented by the class [Parameter](https://api.nette.org/php-generator/master/Nette/PhpGenerator/Parameter.html). Again, you can set all conceivable properties:
-
-
```php
-
$method->addParameter('items', []) // $items = []
-
->setReference() // &$items = []
-
->setType('array'); // array &$items = []
-
-
// function count(&$items = [])
-
```
-
-
To define the so-called variadics parameters (or also the splat, spread, ellipsis, unpacking or three dots operator), use `setVariadic()`:
-
-
```php
-
$method = $class->addMethod('count');
-
$method->setVariadic(true);
-
$method->addParameter('items');
-
```
-
-
This generates:
-
-
```php
-
function count(...$items)
-
{
-
}
-
```
-
-
 <!---->
-
-
Method and Function Bodies
-
--------------------------
-
-
The body can be passed all at once to the `setBody()` method or gradually (line by line) by repeatedly calling `addBody()`:
-
-
```php
-
$function = new Nette\PhpGenerator\GlobalFunction('foo');
-
$function->addBody('$a = rand(10, 20);');
-
$function->addBody('return $a;');
-
echo $function;
-
```
-
-
The result is:
-
-
```php
-
function foo()
-
{
-
$a = rand(10, 20);
-
return $a;
-
}
-
```
-
-
You can use special placeholders for easy variable insertion.
-
-
Simple placeholders `?`
-
-
```php
-
$str = 'any string';
-
$num = 3;
-
$function = new Nette\PhpGenerator\GlobalFunction('foo');
-
$function->addBody('return substr(?, ?);', [$str, $num]);
-
echo $function;
-
```
-
-
The result is:
-
-
```php
-
function foo()
-
{
-
return substr('any string', 3);
-
}
-
```
-
-
Placeholder for variadic `...?`
-
-
```php
-
$items = [1, 2, 3];
-
$function = new Nette\PhpGenerator\GlobalFunction('foo');
-
$function->setBody('myfunc(...?);', [$items]);
-
echo $function;
-
```
-
-
The result is:
-
-
```php
-
function foo()
-
{
-
myfunc(1, 2, 3);
-
}
-
```
-
-
You can also use named parameters for PHP 8 with `...?:`
-
-
```php
-
$items = ['foo' => 1, 'bar' => true];
-
$function->setBody('myfunc(...?:);', [$items]);
-
-
// myfunc(foo: 1, bar: true);
-
```
-
-
The placeholder is escaped with a backslash `\?`
-
-
```php
-
$num = 3;
-
$function = new Nette\PhpGenerator\GlobalFunction('foo');
-
$function->addParameter('a');
-
$function->addBody('return $a \? 10 : ?;', [$num]);
-
echo $function;
-
```
-
-
The result is:
-
-
```php
-
function foo($a)
-
{
-
return $a ? 10 : 3;
-
}
-
```
-
-
 <!---->
-
-
Printer and PSR Compliance
-
--------------------------
-
-
The [Printer](https://api.nette.org/php-generator/master/Nette/PhpGenerator/Printer.html) class is used for generating PHP code:
-
-
```php
-
$class = new Nette\PhpGenerator\ClassType('Demo');
-
// ...
-
-
$printer = new Nette\PhpGenerator\Printer;
-
echo $printer->printClass($class); // same as: echo $class
-
```
-
-
It can generate code for all other elements, offering methods like `printFunction()`, `printNamespace()`, etc.
-
-
There's also the `PsrPrinter` class, which outputs in accordance with PSR-2 / PSR-12 / PER coding style:
-
-
```php
-
$printer = new Nette\PhpGenerator\PsrPrinter;
-
echo $printer->printClass($class);
-
```
-
-
Need custom behavior? Create your own version by inheriting the `Printer` class. You can reconfigure these variables:
-
-
```php
-
class MyPrinter extends Nette\PhpGenerator\Printer
-
{
-
// length of the line after which the line will break
-
public int $wrapLength = 120;
-
// indentation character, can be replaced with a sequence of spaces
-
public string $indentation = "\t";
-
// number of blank lines between properties
-
public int $linesBetweenProperties = 0;
-
// number of blank lines between methods
-
public int $linesBetweenMethods = 2;
-
// number of blank lines between 'use statements' groups for classes, functions, and constants
-
public int $linesBetweenUseTypes = 0;
-
// position of the opening curly brace for functions and methods
-
public bool $bracesOnNextLine = true;
-
// place one parameter on one line, even if it has an attribute or is supported
-
public bool $singleParameterOnOneLine = false;
-
// omits namespaces that do not contain any class or function
-
public bool $omitEmptyNamespaces = true;
-
// separator between the right parenthesis and return type of functions and methods
-
public string $returnTypeColon = ': ';
-
}
-
```
-
-
How and why does the standard `Printer` differ from `PsrPrinter`? Why isn't there just one printer, the `PsrPrinter`, in the package?
-
-
The standard `Printer` formats the code as we do throughout Nette. Since Nette was established much earlier than PSR, and also because PSR took years to deliver standards on time, sometimes even several years after introducing a new feature in PHP, it resulted in a [coding standard](https://doc.nette.org/en/contributing/coding-standard) that differs in a few minor aspects.
-
The major difference is the use of tabs instead of spaces. We know that by using tabs in our projects, we allow for width customization, which is [essential for people with visual impairments](https://doc.nette.org/en/contributing/coding-standard#toc-tabs-instead-of-spaces).
-
An example of a minor difference is placing the curly brace on a separate line for functions and methods, always. The PSR recommendation seems illogical to us and [leads to reduced code clarity](https://doc.nette.org/en/contributing/coding-standard#toc-wrapping-and-braces).
-
-
 <!---->
-
-
Types
-
-----
-
-
Every type or union/intersection type can be passed as a string; you can also use predefined constants for native types:
-
-
```php
-
use Nette\PhpGenerator\Type;
-
-
$member->setType('array'); // or Type::Array;
-
$member->setType('?array'); // or Type::nullable(Type::Array);
-
$member->setType('array|string'); // or Type::union(Type::Array, Type::String)
-
$member->setType('Foo&Bar'); // or Type::intersection(Foo::class, Bar::class)
-
$member->setType(null); // removes the type
-
```
-
-
The same applies to the `setReturnType()` method.
-
-
 <!---->
-
-
Literals
-
--------
-
-
Using `Literal`, you can pass any PHP code, for example, for default property values or parameters, etc:
-
-
```php
-
use Nette\PhpGenerator\Literal;
-
-
$class = new Nette\PhpGenerator\ClassType('Demo');
-
-
$class->addProperty('foo', new Literal('Iterator::SELF_FIRST'));
-
-
$class->addMethod('bar')
-
->addParameter('id', new Literal('1 + 2'));
-
-
echo $class;
-
```
-
-
Result:
-
-
```php
-
class Demo
-
{
-
public $foo = Iterator::SELF_FIRST;
-
-
public function bar($id = 1 + 2)
-
{
-
}
-
}
-
```
-
-
You can also pass parameters to `Literal` and have them formatted into valid PHP code using [placeholders](#method-and-function-bodies):
-
-
```php
-
new Literal('substr(?, ?)', [$a, $b]);
-
// generates for example: substr('hello', 5);
-
```
-
-
A literal representing the creation of a new object can easily be generated using the `new` method:
-
-
```php
-
Literal::new(Demo::class, [$a, 'foo' => $b]);
-
// generates for example: new Demo(10, foo: 20)
-
```
-
-
 <!---->
-
-
Attributes
-
----------
-
-
With PHP 8, you can add attributes to all classes, methods, properties, constants, enum cases, functions, closures, and parameters. You can also use [literals](#literals) as parameter values.
-
-
```php
-
$class = new Nette\PhpGenerator\ClassType('Demo');
-
$class->addAttribute('Table', [
-
'name' => 'user',
-
'constraints' => [
-
Literal::new('UniqueConstraint', ['name' => 'ean', 'columns' => ['ean']]),
-
],
-
]);
-
-
$class->addProperty('list')
-
->addAttribute('Deprecated');
-
-
$method = $class->addMethod('count')
-
->addAttribute('Foo\Cached', ['mode' => true]);
-
-
$method->addParameter('items')
-
->addAttribute('Bar');
-
-
echo $class;
-
```
-
-
Result:
-
-
```php
-
#[Table(name: 'user', constraints: [new UniqueConstraint(name: 'ean', columns: ['ean'])])]
-
class Demo
-
{
-
#[Deprecated]
-
public $list;
-
-
-
#[Foo\Cached(mode: true)]
-
public function count(
-
#[Bar]
-
$items,
-
) {
-
}
-
}
-
```
-
-
 <!---->
-
-
Property Hooks
-
--------------
-
-
You can also define property hooks (represented by the class [PropertyHook](https://api.nette.org/php-generator/master/Nette/PhpGenerator/PropertyHook.html)) for get and set operations, a feature introduced in PHP 8.4:
-
-
```php
-
$class = new Nette\PhpGenerator\ClassType('Demo');
-
$prop = $class->addProperty('firstName')
-
->setType('string');
-
-
$prop->addHook('set', 'strtolower($value)')
-
->addParameter('value')
-
->setType('string');
-
-
$prop->addHook('get')
-
->setBody('return ucfirst($this->firstName);');
-
-
echo $class;
-
```
-
-
This generates:
-
-
```php
-
class Demo
-
{
-
public string $firstName {
-
set(string $value) => strtolower($value);
-
get {
-
return ucfirst($this->firstName);
-
}
-
}
-
}
-
```
-
-
Properties and property hooks can be abstract or final:
-
-
```php
-
$class->addProperty('id')
-
->setType('int')
-
->addHook('get')
-
->setAbstract();
-
-
$class->addProperty('role')
-
->setType('string')
-
->addHook('set', 'strtolower($value)')
-
->setFinal();
-
```
-
-
 <!---->
-
-
Asymmetric Visibility
-
---------------------
-
-
PHP 8.4 introduces asymmetric visibility for properties. You can set different access levels for reading and writing.
-
The visibility can be set using either the `setVisibility()` method with two parameters, or by using `setPublic()`, `setProtected()`, or `setPrivate()` with the `mode` parameter that specifies whether the visibility applies to getting or setting the property. The default mode is 'get'.
-
-
```php
-
$class = new Nette\PhpGenerator\ClassType('Demo');
-
-
$class->addProperty('name')
-
->setType('string')
-
->setVisibility('public', 'private'); // public for read, private for write
-
-
$class->addProperty('id')
-
->setType('int')
-
->setProtected('set'); // protected for write
-
-
echo $class;
-
```
-
-
This generates:
-
-
```php
-
class Demo
-
{
-
public private(set) string $name;
-
-
protected(set) int $id;
-
}
-
```
-
-
 <!---->
-
-
Namespace
-
---------
-
-
Classes, traits, interfaces, and enums (hereafter referred to as classes) can be grouped into namespaces represented by the [PhpNamespace](https://api.nette.org/php-generator/master/Nette/PhpGenerator/PhpNamespace.html) class:
-
-
```php
-
$namespace = new Nette\PhpGenerator\PhpNamespace('Foo');
-
-
// create new classes in the namespace
-
$class = $namespace->addClass('Task');
-
$interface = $namespace->addInterface('Countable');
-
$trait = $namespace->addTrait('NameAware');
-
-
// or insert an existing class into the namespace
-
$class = new Nette\PhpGenerator\ClassType('Task');
-
$namespace->add($class);
-
```
-
-
If the class already exists, an exception is thrown.
-
-
You can define use clauses:
-
-
```php
-
// use Http\Request;
-
$namespace->addUse(Http\Request::class);
-
// use Http\Request as HttpReq;
-
$namespace->addUse(Http\Request::class, 'HttpReq');
-
// use function iter\range;
-
$namespace->addUseFunction('iter\range');
-
```
-
-
To simplify a fully qualified class, function, or constant name based on defined aliases, use the `simplifyName` method:
-
-
```php
-
echo $namespace->simplifyName('Foo\Bar'); // 'Bar', because 'Foo' is the current namespace
-
echo $namespace->simplifyName('iter\range', $namespace::NameFunction); // 'range', due to the defined use-statement
-
```
-
-
Conversely, you can convert a simplified class, function, or constant name back to a fully qualified name using the `resolveName` method:
-
-
```php
-
echo $namespace->resolveName('Bar'); // 'Foo\Bar'
-
echo $namespace->resolveName('range', $namespace::NameFunction); // 'iter\range'
-
```
-
-
 <!---->
-
-
Class Names Resolving
-
---------------------
-
-
**When a class is part of a namespace, it's rendered slightly differently:** all types (e.g., type hints, return types, parent class name, implemented interfaces, used traits, and attributes) are automatically *resolved* (unless you turn it off, see below).
-
This means you must use **fully qualified class names** in definitions, and they will be replaced with aliases (based on use clauses) or fully qualified names in the resulting code:
-
-
```php
-
$namespace = new Nette\PhpGenerator\PhpNamespace('Foo');
-
$namespace->addUse('Bar\AliasedClass');
-
-
$class = $namespace->addClass('Demo');
-
$class->addImplement('Foo\A') // will be simplified to A
-
->addTrait('Bar\AliasedClass'); // will be simplified to AliasedClass
-
-
$method = $class->addMethod('method');
-
$method->addComment('@return ' . $namespace->simplifyType('Foo\D')); // we manually simplify in comments
-
$method->addParameter('arg')
-
->setType('Bar\OtherClass'); // will be translated to \Bar\OtherClass
-
-
echo $namespace;
-
-
// or use the PsrPrinter for output in accordance with PSR-2 / PSR-12 / PER
-
// echo (new Nette\PhpGenerator\PsrPrinter)->printNamespace($namespace);
-
```
-
-
Result:
-
-
```php
-
namespace Foo;
-
-
use Bar\AliasedClass;
-
-
class Demo implements A
-
{
-
use AliasedClass;
-
-
/**
-
* @return D
-
*/
-
public function method(\Bar\OtherClass $arg)
-
{
-
}
-
}
-
```
-
-
Auto-resolving can be turned off this way:
-
-
```php
-
$printer = new Nette\PhpGenerator\Printer; // or PsrPrinter
-
$printer->setTypeResolving(false);
-
echo $printer->printNamespace($namespace);
-
```
-
-
 <!---->
-
-
PHP Files
-
---------
-
-
Classes, functions, and namespaces can be grouped into PHP files represented by the [PhpFile](https://api.nette.org/php-generator/master/Nette/PhpGenerator/PhpFile.html) class:
-
-
```php
-
$file = new Nette\PhpGenerator\PhpFile;
-
$file->addComment('This file is auto-generated.');
-
$file->setStrictTypes(); // adds declare(strict_types=1)
-
-
$class = $file->addClass('Foo\A');
-
$function = $file->addFunction('Foo\foo');
-
-
// or
-
// $namespace = $file->addNamespace('Foo');
-
// $class = $namespace->addClass('A');
-
// $function = $namespace->addFunction('foo');
-
-
echo $file;
-
-
// or use the PsrPrinter for output in accordance with PSR-2 / PSR-12 / PER
-
// echo (new Nette\PhpGenerator\PsrPrinter)->printFile($file);
-
```
-
-
Result:
-
-
```php
-
<?php
-
-
/**
-
* This file is auto-generated.
-
*/
-
-
declare(strict_types=1);
-
-
namespace Foo;
-
-
class A
-
{
-
}
-
-
function foo()
-
{
-
}
-
```
-
-
**Please note:** No additional code can be added to the files outside of functions and classes.
-
-
 <!---->
-
-
Generating from Existing Ones
-
-----------------------------
-
-
In addition to being able to model classes and functions using the API described above, you can also have them automatically generated using existing ones:
-
-
```php
-
// creates a class identical to the PDO class
-
$class = Nette\PhpGenerator\ClassType::from(PDO::class);
-
-
// creates a function identical to the trim() function
-
$function = Nette\PhpGenerator\GlobalFunction::from('trim');
-
-
// creates a closure based on the provided one
-
$closure = Nette\PhpGenerator\Closure::from(
-
function (stdClass $a, $b = null) {},
-
);
-
```
-
-
By default, function and method bodies are empty. If you also want to load them, use this method
-
(requires the `nikic/php-parser` package to be installed):
-
-
```php
-
$class = Nette\PhpGenerator\ClassType::from(Foo::class, withBodies: true);
-
-
$function = Nette\PhpGenerator\GlobalFunction::from('foo', withBody: true);
-
```
-
-
 <!---->
-
-
Loading from PHP Files
-
----------------------
-
-
You can also load functions, classes, interfaces, and enums directly from a string containing PHP code. For example, to create a `ClassType` object:
-
-
```php
-
$class = Nette\PhpGenerator\ClassType::fromCode(<<<XX
-
<?php
-
-
class Demo
-
{
-
public $foo;
-
}
-
XX);
-
```
-
-
When loading classes from PHP code, single-line comments outside method bodies are ignored (e.g., for properties, etc.), as this library doesn't have an API to work with them.
-
-
You can also directly load an entire PHP file, which can contain any number of classes, functions, or even namespaces:
-
-
```php
-
$file = Nette\PhpGenerator\PhpFile::fromCode(file_get_contents('classes.php'));
-
```
-
-
The file's initial comment and `strict_types` declaration are also loaded. However, all other global code is ignored.
-
-
It requires `nikic/php-parser` to be installed.
-
-
*(If you need to manipulate global code in files or individual statements in method bodies, it's better to use the `nikic/php-parser` library directly.)*
-
-
 <!---->
-
-
Class Manipulator
-
-----------------
-
-
The [ClassManipulator](https://api.nette.org/php-generator/master/Nette/PhpGenerator/ClassManipulator.html) class provides tools for manipulating classes.
-
-
```php
-
$class = new Nette\PhpGenerator\ClassType('Demo');
-
$manipulator = new Nette\PhpGenerator\ClassManipulator($class);
-
```
-
-
The `inheritMethod()` method copies a method from a parent class or implemented interface into your class. This allows you to override the method or extend its signature:
-
-
```php
-
$method = $manipulator->inheritMethod('bar');
-
$method->setBody('...');
-
```
-
-
The `inheritProperty()` method copies a property from a parent class into your class. This is useful when you want to have the same property in your class, but possibly with a different default value:
-
-
```php
-
$property = $manipulator->inheritProperty('foo');
-
$property->setValue('new value');
-
```
-
-
The `implement()` method automatically implements all methods and properties from the given interface or abstract class:
-
-
```php
-
$manipulator->implement(SomeInterface::class);
-
// Now your class implements SomeInterface and includes all its methods
-
```
-
-
 <!---->
-
-
Variable Dumping
-
----------------
-
-
The `Dumper` class converts a variable into parseable PHP code. It provides a better and clearer output than the standard `var_export()` function.
-
-
```php
-
$dumper = new Nette\PhpGenerator\Dumper;
-
-
$var = ['a', 'b', 123];
-
-
echo $dumper->dump($var); // outputs ['a', 'b', 123]
-
```
-49
vendor/nette/php-generator/src/PhpGenerator/Attribute.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
-
-
/**
-
* Definition of a PHP attribute.
-
*/
-
final class Attribute
-
{
-
private string $name;
-
-
/** @var mixed[] */
-
private array $args;
-
-
-
/** @param mixed[] $args */
-
public function __construct(string $name, array $args)
-
{
-
if (!Helpers::isNamespaceIdentifier($name)) {
-
throw new Nette\InvalidArgumentException("Value '$name' is not valid attribute name.");
-
}
-
-
$this->name = $name;
-
$this->args = $args;
-
}
-
-
-
public function getName(): string
-
{
-
return $this->name;
-
}
-
-
-
/** @return mixed[] */
-
public function getArguments(): array
-
{
-
return $this->args;
-
}
-
}
-148
vendor/nette/php-generator/src/PhpGenerator/ClassLike.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use function array_map, is_object, strtolower;
-
-
-
/**
-
* Base definition of class, interface, trait or enum type.
-
*/
-
abstract class ClassLike
-
{
-
use Traits\CommentAware;
-
use Traits\AttributeAware;
-
-
#[\Deprecated('Use Visibility::Public')]
-
public const VisibilityPublic = Visibility::Public,
-
VISIBILITY_PUBLIC = Visibility::Public;
-
-
#[\Deprecated('Use Visibility::Protected')]
-
public const VisibilityProtected = Visibility::Protected,
-
VISIBILITY_PROTECTED = Visibility::Protected;
-
-
#[\Deprecated('Use Visibility::Private')]
-
public const VisibilityPrivate = Visibility::Private,
-
VISIBILITY_PRIVATE = Visibility::Private;
-
-
private ?PhpNamespace $namespace;
-
private ?string $name;
-
-
-
public static function from(string|object $class, bool $withBodies = false): static
-
{
-
$instance = (new Factory)
-
->fromClassReflection(new \ReflectionClass($class), $withBodies);
-
-
if (!$instance instanceof static) {
-
$class = is_object($class) ? $class::class : $class;
-
throw new Nette\InvalidArgumentException("$class cannot be represented with " . static::class . '. Call ' . $instance::class . '::' . __FUNCTION__ . '() or ' . __METHOD__ . '() instead.');
-
}
-
-
return $instance;
-
}
-
-
-
public static function fromCode(string $code): static
-
{
-
$instance = (new Factory)
-
->fromClassCode($code);
-
-
if (!$instance instanceof static) {
-
throw new Nette\InvalidArgumentException('Provided code cannot be represented with ' . static::class . '. Call ' . $instance::class . '::' . __FUNCTION__ . '() or ' . __METHOD__ . '() instead.');
-
}
-
-
return $instance;
-
}
-
-
-
public function __construct(string $name, ?PhpNamespace $namespace = null)
-
{
-
$this->setName($name);
-
$this->namespace = $namespace;
-
}
-
-
-
public function __toString(): string
-
{
-
return (new Printer)->printClass($this, $this->namespace);
-
}
-
-
-
/** @deprecated an object can be in multiple namespaces */
-
public function getNamespace(): ?PhpNamespace
-
{
-
return $this->namespace;
-
}
-
-
-
public function setName(?string $name): static
-
{
-
if ($name !== null && (!Helpers::isIdentifier($name) || isset(Helpers::Keywords[strtolower($name)]))) {
-
throw new Nette\InvalidArgumentException("Value '$name' is not valid class name.");
-
}
-
-
$this->name = $name;
-
return $this;
-
}
-
-
-
public function getName(): ?string
-
{
-
return $this->name;
-
}
-
-
-
public function isClass(): bool
-
{
-
return $this instanceof ClassType;
-
}
-
-
-
public function isInterface(): bool
-
{
-
return $this instanceof InterfaceType;
-
}
-
-
-
public function isTrait(): bool
-
{
-
return $this instanceof TraitType;
-
}
-
-
-
public function isEnum(): bool
-
{
-
return $this instanceof EnumType;
-
}
-
-
-
/** @param string[] $names */
-
protected function validateNames(array $names): void
-
{
-
foreach ($names as $name) {
-
if (!Helpers::isNamespaceIdentifier($name, allowLeadingSlash: true)) {
-
throw new Nette\InvalidArgumentException("Value '$name' is not valid class name.");
-
}
-
}
-
}
-
-
-
public function validate(): void
-
{
-
}
-
-
-
public function __clone(): void
-
{
-
$this->attributes = array_map(fn($attr) => clone $attr, $this->attributes);
-
}
-
}
-124
vendor/nette/php-generator/src/PhpGenerator/ClassManipulator.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use const PHP_VERSION_ID;
-
-
-
final class ClassManipulator
-
{
-
public function __construct(
-
private ClassType $class,
-
) {
-
}
-
-
-
/**
-
* Inherits property from parent class.
-
*/
-
public function inheritProperty(string $name, bool $returnIfExists = false): Property
-
{
-
if ($this->class->hasProperty($name)) {
-
return $returnIfExists
-
? $this->class->getProperty($name)
-
: throw new Nette\InvalidStateException("Cannot inherit property '$name', because it already exists.");
-
}
-
-
$parents = [...(array) $this->class->getExtends(), ...$this->class->getImplements()]
-
?: throw new Nette\InvalidStateException("Class '{$this->class->getName()}' has neither setExtends() nor setImplements() set.");
-
-
foreach ($parents as $parent) {
-
try {
-
$rp = new \ReflectionProperty($parent, $name);
-
} catch (\ReflectionException) {
-
continue;
-
}
-
return $this->implementProperty($rp);
-
}
-
-
throw new Nette\InvalidStateException("Property '$name' has not been found in any ancestor: " . implode(', ', $parents));
-
}
-
-
-
/**
-
* Inherits method from parent class or interface.
-
*/
-
public function inheritMethod(string $name, bool $returnIfExists = false): Method
-
{
-
if ($this->class->hasMethod($name)) {
-
return $returnIfExists
-
? $this->class->getMethod($name)
-
: throw new Nette\InvalidStateException("Cannot inherit method '$name', because it already exists.");
-
}
-
-
$parents = [...(array) $this->class->getExtends(), ...$this->class->getImplements()]
-
?: throw new Nette\InvalidStateException("Class '{$this->class->getName()}' has neither setExtends() nor setImplements() set.");
-
-
foreach ($parents as $parent) {
-
try {
-
$rm = new \ReflectionMethod($parent, $name);
-
} catch (\ReflectionException) {
-
continue;
-
}
-
return $this->implementMethod($rm);
-
}
-
-
throw new Nette\InvalidStateException("Method '$name' has not been found in any ancestor: " . implode(', ', $parents));
-
}
-
-
-
/**
-
* Implements all methods from the given interface or abstract class.
-
*/
-
public function implement(string $name): void
-
{
-
$definition = new \ReflectionClass($name);
-
if ($definition->isInterface()) {
-
$this->class->addImplement($name);
-
} elseif ($definition->isAbstract()) {
-
$this->class->setExtends($name);
-
} else {
-
throw new Nette\InvalidArgumentException("'$name' is not an interface or abstract class.");
-
}
-
-
foreach ($definition->getMethods() as $method) {
-
if (!$this->class->hasMethod($method->getName()) && $method->isAbstract()) {
-
$this->implementMethod($method);
-
}
-
}
-
-
if (PHP_VERSION_ID >= 80400) {
-
foreach ($definition->getProperties() as $property) {
-
if (!$this->class->hasProperty($property->getName()) && $property->isAbstract()) {
-
$this->implementProperty($property);
-
}
-
}
-
}
-
}
-
-
-
private function implementMethod(\ReflectionMethod $rm): Method
-
{
-
$method = (new Factory)->fromMethodReflection($rm);
-
$method->setAbstract(false);
-
$this->class->addMember($method);
-
return $method;
-
}
-
-
-
private function implementProperty(\ReflectionProperty $rp): Property
-
{
-
$property = (new Factory)->fromPropertyReflection($rp);
-
$property->setHooks([])->setAbstract(false);
-
$this->class->addMember($property);
-
return $property;
-
}
-
}
-198
vendor/nette/php-generator/src/PhpGenerator/ClassType.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use function array_diff, array_map, strtolower;
-
-
-
/**
-
* Definition of a class with properties, methods, constants, traits and PHP attributes.
-
*/
-
final class ClassType extends ClassLike
-
{
-
use Traits\ConstantsAware;
-
use Traits\MethodsAware;
-
use Traits\PropertiesAware;
-
use Traits\TraitsAware;
-
-
#[\Deprecated]
-
public const
-
TYPE_CLASS = 'class',
-
TYPE_INTERFACE = 'interface',
-
TYPE_TRAIT = 'trait',
-
TYPE_ENUM = 'enum';
-
-
private bool $final = false;
-
private bool $abstract = false;
-
private ?string $extends = null;
-
private bool $readOnly = false;
-
-
/** @var string[] */
-
private array $implements = [];
-
-
-
public function __construct(?string $name = null, ?PhpNamespace $namespace = null)
-
{
-
if ($name === null) {
-
parent::__construct('foo', $namespace);
-
$this->setName(null);
-
} else {
-
parent::__construct($name, $namespace);
-
}
-
}
-
-
-
public function setFinal(bool $state = true): static
-
{
-
$this->final = $state;
-
return $this;
-
}
-
-
-
public function isFinal(): bool
-
{
-
return $this->final;
-
}
-
-
-
public function setAbstract(bool $state = true): static
-
{
-
$this->abstract = $state;
-
return $this;
-
}
-
-
-
public function isAbstract(): bool
-
{
-
return $this->abstract;
-
}
-
-
-
public function setReadOnly(bool $state = true): static
-
{
-
$this->readOnly = $state;
-
return $this;
-
}
-
-
-
public function isReadOnly(): bool
-
{
-
return $this->readOnly;
-
}
-
-
-
public function setExtends(?string $name): static
-
{
-
if ($name) {
-
$this->validateNames([$name]);
-
}
-
$this->extends = $name;
-
return $this;
-
}
-
-
-
public function getExtends(): ?string
-
{
-
return $this->extends;
-
}
-
-
-
/**
-
* @param string[] $names
-
*/
-
public function setImplements(array $names): static
-
{
-
$this->validateNames($names);
-
$this->implements = $names;
-
return $this;
-
}
-
-
-
/** @return string[] */
-
public function getImplements(): array
-
{
-
return $this->implements;
-
}
-
-
-
public function addImplement(string $name): static
-
{
-
$this->validateNames([$name]);
-
$this->implements[] = $name;
-
return $this;
-
}
-
-
-
public function removeImplement(string $name): static
-
{
-
$this->implements = array_diff($this->implements, [$name]);
-
return $this;
-
}
-
-
-
public function addMember(Method|Property|Constant|TraitUse $member, bool $overwrite = false): static
-
{
-
$name = $member->getName();
-
[$type, $n] = match (true) {
-
$member instanceof Constant => ['consts', $name],
-
$member instanceof Method => ['methods', strtolower($name)],
-
$member instanceof Property => ['properties', $name],
-
$member instanceof TraitUse => ['traits', $name],
-
};
-
if (!$overwrite && isset($this->$type[$n])) {
-
throw new Nette\InvalidStateException("Cannot add member '$name', because it already exists.");
-
}
-
$this->$type[$n] = $member;
-
return $this;
-
}
-
-
-
/**
-
* @deprecated use ClassManipulator::inheritProperty()
-
*/
-
public function inheritProperty(string $name, bool $returnIfExists = false): Property
-
{
-
return (new ClassManipulator($this))->inheritProperty($name, $returnIfExists);
-
}
-
-
-
/**
-
* @deprecated use ClassManipulator::inheritMethod()
-
*/
-
public function inheritMethod(string $name, bool $returnIfExists = false): Method
-
{
-
return (new ClassManipulator($this))->inheritMethod($name, $returnIfExists);
-
}
-
-
-
/** @throws Nette\InvalidStateException */
-
public function validate(): void
-
{
-
$name = $this->getName();
-
if ($name === null && ($this->abstract || $this->final)) {
-
throw new Nette\InvalidStateException('Anonymous class cannot be abstract or final.');
-
-
} elseif ($this->abstract && $this->final) {
-
throw new Nette\InvalidStateException("Class '$name' cannot be abstract and final at the same time.");
-
}
-
}
-
-
-
public function __clone(): void
-
{
-
parent::__clone();
-
$clone = fn($item) => clone $item;
-
$this->consts = array_map($clone, $this->consts);
-
$this->methods = array_map($clone, $this->methods);
-
$this->properties = array_map($clone, $this->properties);
-
$this->traits = array_map($clone, $this->traits);
-
}
-
}
-66
vendor/nette/php-generator/src/PhpGenerator/Closure.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
-
/**
-
* Definition of a closure.
-
*/
-
final class Closure
-
{
-
use Traits\FunctionLike;
-
use Traits\AttributeAware;
-
-
/** @var Parameter[] */
-
private array $uses = [];
-
-
-
public static function from(\Closure $closure): self
-
{
-
return (new Factory)->fromFunctionReflection(new \ReflectionFunction($closure));
-
}
-
-
-
public function __toString(): string
-
{
-
return (new Printer)->printClosure($this);
-
}
-
-
-
/**
-
* Replaces all uses.
-
* @param Parameter[] $uses
-
*/
-
public function setUses(array $uses): static
-
{
-
(function (Parameter ...$uses) {})(...$uses);
-
$this->uses = $uses;
-
return $this;
-
}
-
-
-
/** @return Parameter[] */
-
public function getUses(): array
-
{
-
return $this->uses;
-
}
-
-
-
public function addUse(string $name): Parameter
-
{
-
return $this->uses[] = new Parameter($name);
-
}
-
-
-
public function __clone(): void
-
{
-
$this->parameters = array_map(fn($param) => clone $param, $this->parameters);
-
}
-
}
-66
vendor/nette/php-generator/src/PhpGenerator/Constant.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
-
/**
-
* Definition of a class constant.
-
*/
-
final class Constant
-
{
-
use Traits\NameAware;
-
use Traits\VisibilityAware;
-
use Traits\CommentAware;
-
use Traits\AttributeAware;
-
-
private mixed $value;
-
private bool $final = false;
-
private ?string $type = null;
-
-
-
public function setValue(mixed $val): static
-
{
-
$this->value = $val;
-
return $this;
-
}
-
-
-
public function getValue(): mixed
-
{
-
return $this->value;
-
}
-
-
-
public function setFinal(bool $state = true): static
-
{
-
$this->final = $state;
-
return $this;
-
}
-
-
-
public function isFinal(): bool
-
{
-
return $this->final;
-
}
-
-
-
public function setType(?string $type): static
-
{
-
Helpers::validateType($type);
-
$this->type = $type;
-
return $this;
-
}
-
-
-
public function getType(): ?string
-
{
-
return $this->type;
-
}
-
}
-288
vendor/nette/php-generator/src/PhpGenerator/Dumper.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use function addcslashes, array_keys, array_shift, count, dechex, implode, in_array, is_array, is_int, is_object, is_resource, is_string, ltrim, method_exists, ord, preg_match, preg_replace, preg_replace_callback, preg_split, range, serialize, str_contains, str_pad, str_repeat, str_replace, strlen, strrpos, strtoupper, substr, trim, unserialize, var_export;
-
use const PREG_SPLIT_DELIM_CAPTURE, STR_PAD_LEFT;
-
-
-
/**
-
* Generates a PHP representation of a variable.
-
*/
-
final class Dumper
-
{
-
private const IndentLength = 4;
-
-
public int $maxDepth = 50;
-
public int $wrapLength = 120;
-
public string $indentation = "\t";
-
public bool $customObjects = true;
-
-
-
/**
-
* Returns a PHP representation of a variable.
-
*/
-
public function dump(mixed $var, int $column = 0): string
-
{
-
return $this->dumpVar($var, [], 0, $column);
-
}
-
-
-
/** @param array<mixed[]|object> $parents */
-
private function dumpVar(mixed $var, array $parents = [], int $level = 0, int $column = 0): string
-
{
-
if ($var === null) {
-
return 'null';
-
-
} elseif (is_string($var)) {
-
return $this->dumpString($var);
-
-
} elseif (is_array($var)) {
-
return $this->dumpArray($var, $parents, $level, $column);
-
-
} elseif ($var instanceof Literal) {
-
return $this->dumpLiteral($var, $level);
-
-
} elseif (is_object($var)) {
-
return $this->dumpObject($var, $parents, $level, $column);
-
-
} elseif (is_resource($var)) {
-
throw new Nette\InvalidStateException('Cannot dump value of type resource.');
-
-
} else {
-
return var_export($var, return: true);
-
}
-
}
-
-
-
private function dumpString(string $s): string
-
{
-
$special = [
-
"\r" => '\r',
-
"\n" => '\n',
-
"\t" => '\t',
-
"\e" => '\e',
-
'\\' => '\\\\',
-
];
-
-
$utf8 = preg_match('##u', $s);
-
$escaped = preg_replace_callback(
-
$utf8 ? '#[\p{C}\\\]#u' : '#[\x00-\x1F\x7F-\xFF\\\]#',
-
fn($m) => $special[$m[0]] ?? (strlen($m[0]) === 1
-
? '\x' . str_pad(strtoupper(dechex(ord($m[0]))), 2, '0', STR_PAD_LEFT)
-
: '\u{' . strtoupper(ltrim(dechex(self::utf8Ord($m[0])), '0')) . '}'),
-
$s,
-
);
-
return $s === str_replace('\\\\', '\\', $escaped)
-
? "'" . preg_replace('#\'|\\\(?=[\'\\\]|$)#D', '\\\$0', $s) . "'"
-
: '"' . addcslashes($escaped, '"$') . '"';
-
}
-
-
-
private static function utf8Ord(string $c): int
-
{
-
$ord0 = ord($c[0]);
-
return match (true) {
-
$ord0 < 0x80 => $ord0,
-
$ord0 < 0xE0 => ($ord0 << 6) + ord($c[1]) - 0x3080,
-
$ord0 < 0xF0 => ($ord0 << 12) + (ord($c[1]) << 6) + ord($c[2]) - 0xE2080,
-
default => ($ord0 << 18) + (ord($c[1]) << 12) + (ord($c[2]) << 6) + ord($c[3]) - 0x3C82080,
-
};
-
}
-
-
-
/**
-
* @param mixed[] $var
-
* @param array<mixed[]|object> $parents
-
*/
-
private function dumpArray(array $var, array $parents, int $level, int $column): string
-
{
-
if (empty($var)) {
-
return '[]';
-
-
} elseif ($level > $this->maxDepth || in_array($var, $parents, strict: true)) {
-
throw new Nette\InvalidStateException('Nesting level too deep or recursive dependency.');
-
}
-
-
$parents[] = $var;
-
$hideKeys = is_int(($keys = array_keys($var))[0]) && $keys === range($keys[0], $keys[0] + count($var) - 1);
-
$pairs = [];
-
-
foreach ($var as $k => $v) {
-
$keyPart = $hideKeys && ($k !== $keys[0] || $k === 0)
-
? ''
-
: $this->dumpVar($k) . ' => ';
-
$pairs[] = $keyPart . $this->dumpVar($v, $parents, $level + 1, strlen($keyPart) + 1); // 1 = comma after item
-
}
-
-
$line = '[' . implode(', ', $pairs) . ']';
-
$space = str_repeat($this->indentation, $level);
-
return !str_contains($line, "\n") && $level * self::IndentLength + $column + strlen($line) <= $this->wrapLength
-
? $line
-
: "[\n$space" . $this->indentation . implode(",\n$space" . $this->indentation, $pairs) . ",\n$space]";
-
}
-
-
-
/** @param array<mixed[]|object> $parents */
-
private function dumpObject(object $var, array $parents, int $level, int $column): string
-
{
-
if ($level > $this->maxDepth || in_array($var, $parents, strict: true)) {
-
throw new Nette\InvalidStateException('Nesting level too deep or recursive dependency.');
-
} elseif ((new \ReflectionObject($var))->isAnonymous()) {
-
throw new Nette\InvalidStateException('Cannot dump an instance of an anonymous class.');
-
}
-
-
$class = $var::class;
-
$parents[] = $var;
-
-
if ($class === \stdClass::class) {
-
$var = (array) $var;
-
return '(object) ' . $this->dumpArray($var, $parents, $level, $column + 10);
-
-
} elseif ($class === \DateTime::class || $class === \DateTimeImmutable::class) {
-
return $this->format(
-
"new \\$class(?, new \\DateTimeZone(?))",
-
$var->format('Y-m-d H:i:s.u'),
-
$var->getTimeZone()->getName(),
-
);
-
-
} elseif ($var instanceof \UnitEnum) {
-
return '\\' . $var::class . '::' . $var->name;
-
-
} elseif ($var instanceof \Closure) {
-
$inner = Nette\Utils\Callback::unwrap($var);
-
if (Nette\Utils\Callback::isStatic($inner)) {
-
return implode('::', (array) $inner) . '(...)';
-
}
-
-
throw new Nette\InvalidStateException('Cannot dump object of type Closure.');
-
-
} elseif ($this->customObjects) {
-
return $this->dumpCustomObject($var, $parents, $level);
-
-
} else {
-
throw new Nette\InvalidStateException("Cannot dump object of type $class.");
-
}
-
}
-
-
-
/** @param array<mixed[]|object> $parents */
-
private function dumpCustomObject(object $var, array $parents, int $level): string
-
{
-
$class = $var::class;
-
$space = str_repeat($this->indentation, $level);
-
$out = "\n";
-
-
if (method_exists($var, '__serialize')) {
-
$arr = $var->__serialize();
-
} else {
-
$arr = (array) $var;
-
if (method_exists($var, '__sleep')) {
-
foreach ($var->__sleep() as $v) {
-
$props[$v] = $props["\x00*\x00$v"] = $props["\x00$class\x00$v"] = true;
-
}
-
}
-
}
-
-
foreach ($arr as $k => $v) {
-
if (!isset($props) || isset($props[$k])) {
-
$out .= $space . $this->indentation
-
. ($keyPart = $this->dumpVar($k) . ' => ')
-
. $this->dumpVar($v, $parents, $level + 1, strlen($keyPart))
-
. ",\n";
-
}
-
}
-
-
return '\\' . self::class . "::createObject(\\$class::class, [$out$space])";
-
}
-
-
-
private function dumpLiteral(Literal $var, int $level): string
-
{
-
$s = $var->formatWith($this);
-
$s = Nette\Utils\Strings::unixNewLines($s);
-
$s = Nette\Utils\Strings::indent(trim($s), $level, $this->indentation);
-
return ltrim($s, $this->indentation);
-
}
-
-
-
/**
-
* Generates PHP statement. Supports placeholders: ? \? $? ->? ::? ...? ...?: ?*
-
*/
-
public function format(string $statement, mixed ...$args): string
-
{
-
$tokens = preg_split('#(\.\.\.\?:?|\$\?|->\?|::\?|\\\\\?|\?\*|\?(?!\w))#', $statement, -1, PREG_SPLIT_DELIM_CAPTURE);
-
$res = '';
-
foreach ($tokens as $n => $token) {
-
if ($n % 2 === 0) {
-
$res .= $token;
-
} elseif ($token === '\?') {
-
$res .= '?';
-
} elseif (!$args) {
-
throw new Nette\InvalidArgumentException('Insufficient number of arguments.');
-
} elseif ($token === '?') {
-
$res .= $this->dump(array_shift($args), strlen($res) - strrpos($res, "\n"));
-
} elseif ($token === '...?' || $token === '...?:' || $token === '?*') {
-
$arg = array_shift($args);
-
if (!is_array($arg)) {
-
throw new Nette\InvalidArgumentException('Argument must be an array.');
-
}
-
-
$res .= $this->dumpArguments($arg, strlen($res) - strrpos($res, "\n"), $token === '...?:');
-
-
} else { // $ -> ::
-
$arg = array_shift($args);
-
if ($arg instanceof Literal || !Helpers::isIdentifier($arg)) {
-
$arg = '{' . $this->dumpVar($arg) . '}';
-
}
-
-
$res .= substr($token, 0, -1) . $arg;
-
}
-
}
-
-
if ($args) {
-
throw new Nette\InvalidArgumentException('Insufficient number of placeholders.');
-
}
-
-
return $res;
-
}
-
-
-
/** @param mixed[] $args */
-
private function dumpArguments(array $args, int $column, bool $named): string
-
{
-
$pairs = [];
-
foreach ($args as $k => $v) {
-
$name = $named && !is_int($k) ? $k . ': ' : '';
-
$pairs[] = $name . $this->dumpVar($v, [$args], 0, $column + strlen($name) + 1); // 1 = ) after args
-
}
-
-
$line = implode(', ', $pairs);
-
return count($args) < 2 || (!str_contains($line, "\n") && $column + strlen($line) <= $this->wrapLength)
-
? $line
-
: "\n" . $this->indentation . implode(",\n" . $this->indentation, $pairs) . ",\n";
-
}
-
-
-
/**
-
* @param mixed[] $props
-
* @internal
-
*/
-
public static function createObject(string $class, array $props): object
-
{
-
if (method_exists($class, '__serialize')) {
-
$obj = (new \ReflectionClass($class))->newInstanceWithoutConstructor();
-
$obj->__unserialize($props);
-
return $obj;
-
}
-
return unserialize('O' . substr(serialize($class), 1, -1) . substr(serialize($props), 1));
-
}
-
}
-36
vendor/nette/php-generator/src/PhpGenerator/EnumCase.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
-
/**
-
* Definition of an enum case.
-
*/
-
final class EnumCase
-
{
-
use Traits\NameAware;
-
use Traits\CommentAware;
-
use Traits\AttributeAware;
-
-
private string|int|Literal|null $value = null;
-
-
-
public function setValue(string|int|Literal|null $val): static
-
{
-
$this->value = $val;
-
return $this;
-
}
-
-
-
public function getValue(): string|int|Literal|null
-
{
-
return $this->value;
-
}
-
}
-148
vendor/nette/php-generator/src/PhpGenerator/EnumType.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
-
-
/**
-
* Definition of an enum with cases, methods, constants and traits.
-
*/
-
final class EnumType extends ClassLike
-
{
-
use Traits\ConstantsAware;
-
use Traits\MethodsAware;
-
use Traits\TraitsAware;
-
-
/** @var string[] */
-
private array $implements = [];
-
-
/** @var array<string, EnumCase> */
-
private array $cases = [];
-
private ?string $type = null;
-
-
-
public function setType(?string $type): static
-
{
-
$this->type = $type;
-
return $this;
-
}
-
-
-
public function getType(): ?string
-
{
-
return $this->type;
-
}
-
-
-
/**
-
* @param string[] $names
-
*/
-
public function setImplements(array $names): static
-
{
-
$this->validateNames($names);
-
$this->implements = $names;
-
return $this;
-
}
-
-
-
/** @return string[] */
-
public function getImplements(): array
-
{
-
return $this->implements;
-
}
-
-
-
public function addImplement(string $name): static
-
{
-
$this->validateNames([$name]);
-
$this->implements[] = $name;
-
return $this;
-
}
-
-
-
public function removeImplement(string $name): static
-
{
-
$this->implements = array_diff($this->implements, [$name]);
-
return $this;
-
}
-
-
-
/**
-
* Sets cases to enum
-
* @param EnumCase[] $cases
-
*/
-
public function setCases(array $cases): static
-
{
-
(function (EnumCase ...$cases) {})(...$cases);
-
$this->cases = [];
-
foreach ($cases as $case) {
-
$this->cases[$case->getName()] = $case;
-
}
-
-
return $this;
-
}
-
-
-
/** @return EnumCase[] */
-
public function getCases(): array
-
{
-
return $this->cases;
-
}
-
-
-
/** Adds case to enum */
-
public function addCase(string $name, string|int|Literal|null $value = null, bool $overwrite = false): EnumCase
-
{
-
if (!$overwrite && isset($this->cases[$name])) {
-
throw new Nette\InvalidStateException("Cannot add cases '$name', because it already exists.");
-
}
-
return $this->cases[$name] = (new EnumCase($name))
-
->setValue($value);
-
}
-
-
-
public function removeCase(string $name): static
-
{
-
unset($this->cases[$name]);
-
return $this;
-
}
-
-
-
/**
-
* Adds a member. If it already exists, throws an exception or overwrites it if $overwrite is true.
-
*/
-
public function addMember(Method|Constant|EnumCase|TraitUse $member, bool $overwrite = false): static
-
{
-
$name = $member->getName();
-
[$type, $n] = match (true) {
-
$member instanceof Constant => ['consts', $name],
-
$member instanceof Method => ['methods', strtolower($name)],
-
$member instanceof TraitUse => ['traits', $name],
-
$member instanceof EnumCase => ['cases', $name],
-
};
-
if (!$overwrite && isset($this->$type[$n])) {
-
throw new Nette\InvalidStateException("Cannot add member '$name', because it already exists.");
-
}
-
$this->$type[$n] = $member;
-
return $this;
-
}
-
-
-
public function __clone(): void
-
{
-
parent::__clone();
-
$clone = fn($item) => clone $item;
-
$this->consts = array_map($clone, $this->consts);
-
$this->methods = array_map($clone, $this->methods);
-
$this->traits = array_map($clone, $this->traits);
-
$this->cases = array_map($clone, $this->cases);
-
}
-
}
-595
vendor/nette/php-generator/src/PhpGenerator/Extractor.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use PhpParser;
-
use PhpParser\Modifiers;
-
use PhpParser\Node;
-
use PhpParser\NodeFinder;
-
use PhpParser\ParserFactory;
-
use function addcslashes, array_map, assert, class_exists, end, in_array, is_array, rtrim, str_contains, str_repeat, str_replace, str_starts_with, strlen, substr, substr_replace, usort;
-
-
-
/**
-
* Extracts information from PHP code.
-
* @internal
-
*/
-
final class Extractor
-
{
-
private string $code;
-
-
/** @var Node[] */
-
private array $statements;
-
private PhpParser\PrettyPrinterAbstract $printer;
-
-
-
public function __construct(string $code)
-
{
-
if (!class_exists(ParserFactory::class)) {
-
throw new Nette\NotSupportedException("PHP-Parser is required to load method bodies, install package 'nikic/php-parser' 4.7 or newer.");
-
}
-
-
$this->printer = new PhpParser\PrettyPrinter\Standard;
-
$this->parseCode($code);
-
}
-
-
-
private function parseCode(string $code): void
-
{
-
if (!str_starts_with($code, '<?php')) {
-
throw new Nette\InvalidStateException('The input string is not a PHP code.');
-
}
-
-
$this->code = Nette\Utils\Strings::unixNewLines($code);
-
$parser = (new ParserFactory)->createForNewestSupportedVersion();
-
$stmts = $parser->parse($this->code);
-
-
$traverser = new PhpParser\NodeTraverser;
-
$traverser->addVisitor(new PhpParser\NodeVisitor\ParentConnectingVisitor);
-
$traverser->addVisitor(new PhpParser\NodeVisitor\NameResolver(null, ['preserveOriginalNames' => true]));
-
$this->statements = $traverser->traverse($stmts);
-
}
-
-
-
/** @return array<string, string> */
-
public function extractMethodBodies(string $className): array
-
{
-
$nodeFinder = new NodeFinder;
-
$classNode = $nodeFinder->findFirst(
-
$this->statements,
-
fn(Node $node) => $node instanceof Node\Stmt\ClassLike && $node->namespacedName->toString() === $className,
-
);
-
-
$res = [];
-
foreach ($nodeFinder->findInstanceOf($classNode, Node\Stmt\ClassMethod::class) as $methodNode) {
-
if ($methodNode->stmts) {
-
$res[$methodNode->name->toString()] = $this->getReformattedContents($methodNode->stmts, 2);
-
}
-
}
-
-
return $res;
-
}
-
-
-
/** @return array<string, array<string, array{string, bool}>> */
-
public function extractPropertyHookBodies(string $className): array
-
{
-
if (!class_exists(Node\PropertyHook::class)) {
-
return [];
-
}
-
-
$nodeFinder = new NodeFinder;
-
$classNode = $nodeFinder->findFirst(
-
$this->statements,
-
fn(Node $node) => $node instanceof Node\Stmt\ClassLike && $node->namespacedName->toString() === $className,
-
);
-
-
$res = [];
-
foreach ($nodeFinder->findInstanceOf($classNode, Node\Stmt\Property::class) as $propertyNode) {
-
foreach ($propertyNode->props as $propNode) {
-
$propName = $propNode->name->toString();
-
foreach ($propertyNode->hooks as $hookNode) {
-
$body = $hookNode->body;
-
if ($body !== null) {
-
$contents = $this->getReformattedContents(is_array($body) ? $body : [$body], 3);
-
$res[$propName][$hookNode->name->toString()] = [$contents, !is_array($body)];
-
}
-
}
-
}
-
}
-
return $res;
-
}
-
-
-
public function extractFunctionBody(string $name): string
-
{
-
$functionNode = (new NodeFinder)->findFirst(
-
$this->statements,
-
fn(Node $node) => $node instanceof Node\Stmt\Function_ && $node->namespacedName->toString() === $name,
-
);
-
assert($functionNode instanceof Node\Stmt\Function_);
-
-
return $this->getReformattedContents($functionNode->stmts, 1);
-
}
-
-
-
/** @param Node[] $nodes */
-
private function getReformattedContents(array $nodes, int $level): string
-
{
-
if (!$nodes) {
-
return '';
-
}
-
$body = $this->getNodeContents(...$nodes);
-
$body = $this->performReplacements($body, $this->prepareReplacements($nodes, $level));
-
return Helpers::unindent($body, $level);
-
}
-
-
-
/**
-
* @param Node[] $nodes
-
* @return array<array{int, int, string}>
-
*/
-
private function prepareReplacements(array $nodes, int $level): array
-
{
-
$start = $this->getNodeStartPos($nodes[0]);
-
$replacements = [];
-
$indent = "\n" . str_repeat("\t", $level);
-
(new NodeFinder)->find($nodes, function (Node $node) use (&$replacements, $start, $level, $indent) {
-
if ($node instanceof Node\Name\FullyQualified) {
-
if ($node->getAttribute('originalName') instanceof Node\Name) {
-
$of = match (true) {
-
$node->getAttribute('parent') instanceof Node\Expr\ConstFetch => PhpNamespace::NameConstant,
-
$node->getAttribute('parent') instanceof Node\Expr\FuncCall => PhpNamespace::NameFunction,
-
default => PhpNamespace::NameNormal,
-
};
-
$replacements[] = [
-
$node->getStartFilePos() - $start,
-
$node->getEndFilePos() - $start,
-
Helpers::tagName($node->toCodeString(), $of),
-
];
-
}
-
-
} elseif (
-
$node instanceof Node\Scalar\String_
-
&& in_array($node->getAttribute('kind'), [Node\Scalar\String_::KIND_SINGLE_QUOTED, Node\Scalar\String_::KIND_DOUBLE_QUOTED], true)
-
&& str_contains($node->getAttribute('rawValue'), "\n")
-
) { // multi-line strings -> single line
-
$replacements[] = [
-
$node->getStartFilePos() - $start,
-
$node->getEndFilePos() - $start,
-
'"' . addcslashes($node->value, "\x00..\x1F\"") . '"',
-
];
-
-
} elseif (
-
$node instanceof Node\Scalar\String_
-
&& in_array($node->getAttribute('kind'), [Node\Scalar\String_::KIND_NOWDOC, Node\Scalar\String_::KIND_HEREDOC], true)
-
&& Helpers::unindent($node->getAttribute('docIndentation'), $level) === $node->getAttribute('docIndentation')
-
) { // fix indentation of NOWDOW/HEREDOC
-
$replacements[] = [
-
$node->getStartFilePos() - $start,
-
$node->getEndFilePos() - $start,
-
str_replace("\n", $indent, $this->getNodeContents($node)),
-
];
-
-
} elseif (
-
$node instanceof Node\Scalar\Encapsed
-
&& $node->getAttribute('kind') === Node\Scalar\String_::KIND_DOUBLE_QUOTED
-
) { // multi-line strings -> single line
-
foreach ($node->parts as $part) {
-
if ($part instanceof Node\Scalar\EncapsedStringPart) {
-
$replacements[] = [
-
$part->getStartFilePos() - $start,
-
$part->getEndFilePos() - $start,
-
addcslashes($part->value, "\x00..\x1F\""),
-
];
-
}
-
}
-
} elseif (
-
$node instanceof Node\Scalar\Encapsed && $node->getAttribute('kind') === Node\Scalar\String_::KIND_HEREDOC
-
&& Helpers::unindent($node->getAttribute('docIndentation'), $level) === $node->getAttribute('docIndentation')
-
) { // fix indentation of HEREDOC
-
$replacements[] = [
-
$tmp = $node->getStartFilePos() - $start + strlen($node->getAttribute('docLabel')) + 3, // <<<
-
$tmp,
-
$indent,
-
];
-
$replacements[] = [
-
$tmp = $node->getEndFilePos() - $start - strlen($node->getAttribute('docLabel')),
-
$tmp,
-
$indent,
-
];
-
foreach ($node->parts as $part) {
-
if ($part instanceof Node\Scalar\EncapsedStringPart) {
-
$replacements[] = [
-
$part->getStartFilePos() - $start,
-
$part->getEndFilePos() - $start,
-
str_replace("\n", $indent, $this->getNodeContents($part)),
-
];
-
}
-
}
-
}
-
});
-
return $replacements;
-
}
-
-
-
/** @param array<array{int, int, string}> $replacements */
-
private function performReplacements(string $s, array $replacements): string
-
{
-
usort($replacements, fn($a, $b) => $b[0] <=> $a[0]);
-
-
foreach ($replacements as [$start, $end, $replacement]) {
-
$s = substr_replace($s, $replacement, $start, $end - $start + 1);
-
}
-
-
return $s;
-
}
-
-
-
public function extractAll(): PhpFile
-
{
-
$phpFile = new PhpFile;
-
-
if (
-
$this->statements
-
&& !$this->statements[0] instanceof Node\Stmt\ClassLike
-
&& !$this->statements[0] instanceof Node\Stmt\Function_
-
) {
-
$this->addCommentAndAttributes($phpFile, $this->statements[0]);
-
}
-
-
$namespaces = ['' => $this->statements];
-
foreach ($this->statements as $node) {
-
if ($node instanceof Node\Stmt\Declare_
-
&& $node->declares[0]->key->name === 'strict_types'
-
&& $node->declares[0]->value instanceof Node\Scalar\LNumber
-
) {
-
$phpFile->setStrictTypes((bool) $node->declares[0]->value->value);
-
-
} elseif ($node instanceof Node\Stmt\Namespace_) {
-
$namespaces[$node->name->toString()] = $node->stmts;
-
}
-
}
-
-
foreach ($namespaces as $name => $nodes) {
-
foreach ($nodes as $node) {
-
match (true) {
-
$node instanceof Node\Stmt\Use_ => $this->addUseToNamespace($phpFile->addNamespace($name), $node),
-
$node instanceof Node\Stmt\ClassLike => $this->addClassLikeToFile($phpFile, $node),
-
$node instanceof Node\Stmt\Function_ => $this->addFunctionToFile($phpFile, $node),
-
default => null,
-
};
-
}
-
}
-
-
return $phpFile;
-
}
-
-
-
private function addUseToNamespace(PhpNamespace $namespace, Node\Stmt\Use_ $node): void
-
{
-
$of = [
-
$node::TYPE_NORMAL => PhpNamespace::NameNormal,
-
$node::TYPE_FUNCTION => PhpNamespace::NameFunction,
-
$node::TYPE_CONSTANT => PhpNamespace::NameConstant,
-
][$node->type];
-
foreach ($node->uses as $use) {
-
$namespace->addUse($use->name->toString(), $use->alias?->toString(), $of);
-
}
-
}
-
-
-
private function addClassLikeToFile(PhpFile $phpFile, Node\Stmt\ClassLike $node): ClassLike
-
{
-
if ($node instanceof Node\Stmt\Class_) {
-
$class = $phpFile->addClass($node->namespacedName->toString());
-
$class->setFinal($node->isFinal());
-
$class->setAbstract($node->isAbstract());
-
$class->setReadOnly($node->isReadonly());
-
if ($node->extends) {
-
$class->setExtends($node->extends->toString());
-
}
-
foreach ($node->implements as $item) {
-
$class->addImplement($item->toString());
-
}
-
} elseif ($node instanceof Node\Stmt\Interface_) {
-
$class = $phpFile->addInterface($node->namespacedName->toString());
-
foreach ($node->extends as $item) {
-
$class->addExtend($item->toString());
-
}
-
} elseif ($node instanceof Node\Stmt\Trait_) {
-
$class = $phpFile->addTrait($node->namespacedName->toString());
-
-
} elseif ($node instanceof Node\Stmt\Enum_) {
-
$class = $phpFile->addEnum($node->namespacedName->toString());
-
$class->setType($node->scalarType?->toString());
-
foreach ($node->implements as $item) {
-
$class->addImplement($item->toString());
-
}
-
} else {
-
throw new Nette\ShouldNotHappenException;
-
}
-
-
$this->addCommentAndAttributes($class, $node);
-
$this->addClassMembers($class, $node);
-
return $class;
-
}
-
-
-
private function addClassMembers(ClassLike $class, Node\Stmt\ClassLike $node): void
-
{
-
foreach ($node->stmts as $stmt) {
-
match (true) {
-
$stmt instanceof Node\Stmt\TraitUse => $this->addTraitToClass($class, $stmt),
-
$stmt instanceof Node\Stmt\Property => $this->addPropertyToClass($class, $stmt),
-
$stmt instanceof Node\Stmt\ClassMethod => $this->addMethodToClass($class, $stmt),
-
$stmt instanceof Node\Stmt\ClassConst => $this->addConstantToClass($class, $stmt),
-
$stmt instanceof Node\Stmt\EnumCase => $this->addEnumCaseToClass($class, $stmt),
-
default => null,
-
};
-
}
-
}
-
-
-
private function addTraitToClass(ClassLike $class, Node\Stmt\TraitUse $node): void
-
{
-
foreach ($node->traits as $item) {
-
$trait = $class->addTrait($item->toString());
-
}
-
assert($trait instanceof TraitUse);
-
-
foreach ($node->adaptations as $item) {
-
$trait->addResolution(rtrim($this->getReformattedContents([$item], 0), ';'));
-
}
-
-
$this->addCommentAndAttributes($trait, $node);
-
}
-
-
-
private function addPropertyToClass(ClassLike $class, Node\Stmt\Property $node): void
-
{
-
foreach ($node->props as $item) {
-
$prop = $class->addProperty($item->name->toString());
-
$prop->setStatic($node->isStatic());
-
$prop->setVisibility($this->toVisibility($node->flags), $this->toSetterVisibility($node->flags));
-
$prop->setType($node->type ? $this->toPhp($node->type) : null);
-
if ($item->default) {
-
$prop->setValue($this->toValue($item->default));
-
}
-
-
$prop->setReadOnly($node->isReadonly() || ($class instanceof ClassType && $class->isReadOnly()));
-
$this->addCommentAndAttributes($prop, $node);
-
-
$prop->setAbstract((bool) ($node->flags & Modifiers::ABSTRACT));
-
$prop->setFinal((bool) ($node->flags & Modifiers::FINAL));
-
$this->addHooksToProperty($prop, $node);
-
}
-
}
-
-
-
private function addHooksToProperty(Property|PromotedParameter $prop, Node\Stmt\Property|Node\Param $node): void
-
{
-
if (!class_exists(Node\PropertyHook::class)) {
-
return;
-
}
-
-
foreach ($node->hooks as $hookNode) {
-
$hook = $prop->addHook($hookNode->name->toString());
-
$hook->setFinal((bool) ($hookNode->flags & Modifiers::FINAL));
-
$this->setupFunction($hook, $hookNode);
-
if ($hookNode->body === null) {
-
$hook->setAbstract();
-
} elseif (!is_array($hookNode->body)) {
-
$hook->setBody($this->getReformattedContents([$hookNode->body], 1), short: true);
-
}
-
}
-
}
-
-
-
private function addMethodToClass(ClassLike $class, Node\Stmt\ClassMethod $node): void
-
{
-
$method = $class->addMethod($node->name->toString());
-
$method->setAbstract($node->isAbstract());
-
$method->setFinal($node->isFinal());
-
$method->setStatic($node->isStatic());
-
$method->setVisibility($this->toVisibility($node->flags));
-
$this->setupFunction($method, $node);
-
if ($method->getName() === Method::Constructor && $class instanceof ClassType && $class->isReadOnly()) {
-
array_map(fn($param) => $param instanceof PromotedParameter ? $param->setReadOnly() : $param, $method->getParameters());
-
}
-
}
-
-
-
private function addConstantToClass(ClassLike $class, Node\Stmt\ClassConst $node): void
-
{
-
foreach ($node->consts as $item) {
-
$const = $class->addConstant($item->name->toString(), $this->toValue($item->value));
-
$const->setVisibility($this->toVisibility($node->flags));
-
$const->setFinal($node->isFinal());
-
$this->addCommentAndAttributes($const, $node);
-
}
-
}
-
-
-
private function addEnumCaseToClass(EnumType $class, Node\Stmt\EnumCase $node): void
-
{
-
$value = match (true) {
-
$node->expr === null => null,
-
$node->expr instanceof Node\Scalar\LNumber, $node->expr instanceof Node\Scalar\String_ => $node->expr->value,
-
default => $this->toValue($node->expr),
-
};
-
$case = $class->addCase($node->name->toString(), $value);
-
$this->addCommentAndAttributes($case, $node);
-
}
-
-
-
private function addFunctionToFile(PhpFile $phpFile, Node\Stmt\Function_ $node): void
-
{
-
$function = $phpFile->addFunction($node->namespacedName->toString());
-
$this->setupFunction($function, $node);
-
}
-
-
-
private function addCommentAndAttributes(
-
PhpFile|ClassLike|Constant|Property|GlobalFunction|Method|Parameter|EnumCase|TraitUse|PropertyHook $element,
-
Node $node,
-
): void
-
{
-
if ($node->getDocComment()) {
-
$comment = $node->getDocComment()->getReformattedText();
-
$comment = Helpers::unformatDocComment($comment);
-
$element->setComment($comment);
-
$node->setDocComment(new PhpParser\Comment\Doc(''));
-
}
-
-
foreach ($node->attrGroups ?? [] as $group) {
-
foreach ($group->attrs as $attribute) {
-
$args = [];
-
foreach ($attribute->args as $arg) {
-
if ($arg->name) {
-
$args[$arg->name->toString()] = $this->toValue($arg->value);
-
} else {
-
$args[] = $this->toValue($arg->value);
-
}
-
}
-
-
$element->addAttribute($attribute->name->toString(), $args);
-
}
-
}
-
}
-
-
-
private function setupFunction(GlobalFunction|Method|PropertyHook $function, Node\FunctionLike $node): void
-
{
-
$function->setReturnReference($node->returnsByRef());
-
if (!$function instanceof PropertyHook) {
-
$function->setReturnType($node->getReturnType() ? $this->toPhp($node->getReturnType()) : null);
-
}
-
-
foreach ($node->getParams() as $item) {
-
$getVisibility = $this->toVisibility($item->flags);
-
$setVisibility = $this->toSetterVisibility($item->flags);
-
$final = (bool) ($item->flags & Modifiers::FINAL);
-
if ($getVisibility || $setVisibility || $final) {
-
$param = $function->addPromotedParameter($item->var->name)
-
->setVisibility($getVisibility, $setVisibility)
-
->setReadonly($item->isReadonly())
-
->setFinal($final);
-
$this->addHooksToProperty($param, $item);
-
} else {
-
$param = $function->addParameter($item->var->name);
-
}
-
$param->setType($item->type ? $this->toPhp($item->type) : null);
-
$param->setReference($item->byRef);
-
if (!$function instanceof PropertyHook) {
-
$function->setVariadic($item->variadic);
-
}
-
if ($item->default) {
-
$param->setDefaultValue($this->toValue($item->default));
-
}
-
-
$this->addCommentAndAttributes($param, $item);
-
}
-
-
$this->addCommentAndAttributes($function, $node);
-
if ($node->getStmts()) {
-
$indent = $function instanceof GlobalFunction ? 1 : 2;
-
$function->setBody($this->getReformattedContents($node->getStmts(), $indent));
-
}
-
}
-
-
-
private function toValue(Node\Expr $node): mixed
-
{
-
if ($node instanceof Node\Expr\ConstFetch) {
-
return match ($node->name->toLowerString()) {
-
'null' => null,
-
'true' => true,
-
'false' => false,
-
default => new Literal($this->getReformattedContents([$node], 0)),
-
};
-
} elseif ($node instanceof Node\Scalar\LNumber
-
|| $node instanceof Node\Scalar\DNumber
-
|| $node instanceof Node\Scalar\String_
-
) {
-
return $node->value;
-
-
} elseif ($node instanceof Node\Expr\Array_) {
-
$res = [];
-
foreach ($node->items as $item) {
-
if ($item->unpack) {
-
return new Literal($this->getReformattedContents([$node], 0));
-
-
} elseif ($item->key) {
-
$key = $this->toValue($item->key);
-
if ($key instanceof Literal) {
-
return new Literal($this->getReformattedContents([$node], 0));
-
}
-
-
$res[$key] = $this->toValue($item->value);
-
-
} else {
-
$res[] = $this->toValue($item->value);
-
}
-
}
-
return $res;
-
-
} else {
-
return new Literal($this->getReformattedContents([$node], 0));
-
}
-
}
-
-
-
private function toVisibility(int $flags): ?Visibility
-
{
-
return match (true) {
-
(bool) ($flags & Modifiers::PUBLIC) => Visibility::Public,
-
(bool) ($flags & Modifiers::PROTECTED) => Visibility::Protected,
-
(bool) ($flags & Modifiers::PRIVATE) => Visibility::Private,
-
default => null,
-
};
-
}
-
-
-
private function toSetterVisibility(int $flags): ?Visibility
-
{
-
return match (true) {
-
!class_exists(Node\PropertyHook::class) => null,
-
(bool) ($flags & Modifiers::PUBLIC_SET) => Visibility::Public,
-
(bool) ($flags & Modifiers::PROTECTED_SET) => Visibility::Protected,
-
(bool) ($flags & Modifiers::PRIVATE_SET) => Visibility::Private,
-
default => null,
-
};
-
}
-
-
-
private function toPhp(Node $value): string
-
{
-
$dolly = clone $value;
-
$dolly->setAttribute('comments', []);
-
return $this->printer->prettyPrint([$dolly]);
-
}
-
-
-
private function getNodeContents(Node ...$nodes): string
-
{
-
$start = $this->getNodeStartPos($nodes[0]);
-
return substr($this->code, $start, end($nodes)->getEndFilePos() - $start + 1);
-
}
-
-
-
private function getNodeStartPos(Node $node): int
-
{
-
return ($comments = $node->getComments())
-
? $comments[0]->getStartFilePos()
-
: $node->getStartFilePos();
-
}
-
}
-378
vendor/nette/php-generator/src/PhpGenerator/Factory.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use Nette\Utils\Reflection;
-
use function array_diff, array_filter, array_key_exists, array_map, count, explode, file_get_contents, implode, is_object, is_subclass_of, method_exists, reset;
-
use const PHP_VERSION_ID;
-
-
-
/**
-
* Creates a representations based on reflection or source code.
-
*/
-
final class Factory
-
{
-
/** @var string[][] */
-
private array $bodyCache = [];
-
-
/** @var Extractor[] */
-
private array $extractorCache = [];
-
-
-
/** @param \ReflectionClass<object> $from */
-
public function fromClassReflection(
-
\ReflectionClass $from,
-
bool $withBodies = false,
-
): ClassLike
-
{
-
if ($withBodies && ($from->isAnonymous() || $from->isInternal() || $from->isInterface())) {
-
throw new Nette\NotSupportedException('The $withBodies parameter cannot be used for anonymous or internal classes or interfaces.');
-
}
-
-
$enumIface = null;
-
if ($from->isEnum()) {
-
$class = new EnumType($from->getShortName(), new PhpNamespace($from->getNamespaceName()));
-
$from = new \ReflectionEnum($from->getName());
-
$enumIface = $from->isBacked() ? \BackedEnum::class : \UnitEnum::class;
-
} elseif ($from->isAnonymous()) {
-
$class = new ClassType;
-
} elseif ($from->isInterface()) {
-
$class = new InterfaceType($from->getShortName(), new PhpNamespace($from->getNamespaceName()));
-
} elseif ($from->isTrait()) {
-
$class = new TraitType($from->getShortName(), new PhpNamespace($from->getNamespaceName()));
-
} else {
-
$class = new ClassType($from->getShortName(), new PhpNamespace($from->getNamespaceName()));
-
$class->setFinal($from->isFinal() && $class->isClass());
-
$class->setAbstract($from->isAbstract() && $class->isClass());
-
$class->setReadOnly(PHP_VERSION_ID >= 80200 && $from->isReadOnly());
-
}
-
-
$ifaces = $from->getInterfaceNames();
-
foreach ($ifaces as $iface) {
-
$ifaces = array_filter($ifaces, fn(string $item): bool => !is_subclass_of($iface, $item));
-
}
-
-
if ($from->isInterface()) {
-
$class->setExtends($ifaces);
-
} elseif ($ifaces) {
-
$ifaces = array_diff($ifaces, [$enumIface]);
-
$class->setImplements($ifaces);
-
}
-
-
$class->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
-
$class->setAttributes($this->getAttributes($from));
-
if ($from->getParentClass()) {
-
$class->setExtends($from->getParentClass()->name);
-
$class->setImplements(array_diff($class->getImplements(), $from->getParentClass()->getInterfaceNames()));
-
}
-
-
$props = [];
-
foreach ($from->getProperties() as $prop) {
-
$declaringClass = Reflection::getPropertyDeclaringClass($prop);
-
-
if ($prop->isDefault()
-
&& $declaringClass->name === $from->name
-
&& !$prop->isPromoted()
-
&& !$class->isEnum()
-
) {
-
$props[] = $p = $this->fromPropertyReflection($prop);
-
if ($withBodies) {
-
$hookBodies ??= $this->getExtractor($declaringClass->getFileName())->extractPropertyHookBodies($declaringClass->name);
-
foreach ($hookBodies[$prop->getName()] ?? [] as $hookType => [$body, $short]) {
-
$p->getHook($hookType)->setBody($body, short: $short);
-
}
-
}
-
}
-
}
-
-
if ($props) {
-
$class->setProperties($props);
-
}
-
-
$methods = $resolutions = [];
-
foreach ($from->getMethods() as $method) {
-
$declaringMethod = Reflection::getMethodDeclaringMethod($method);
-
$declaringClass = $declaringMethod->getDeclaringClass();
-
-
if (
-
$declaringClass->name === $from->name
-
&& (!$enumIface || !method_exists($enumIface, $method->name))
-
) {
-
$methods[] = $m = $this->fromMethodReflection($method);
-
if ($withBodies) {
-
$bodies = &$this->bodyCache[$declaringClass->name];
-
$bodies ??= $this->getExtractor($declaringClass->getFileName())->extractMethodBodies($declaringClass->name);
-
if (isset($bodies[$declaringMethod->name])) {
-
$m->setBody($bodies[$declaringMethod->name]);
-
}
-
}
-
}
-
-
$modifier = $declaringMethod->getModifiers() !== $method->getModifiers()
-
? ' ' . $this->getVisibility($method)->value
-
: null;
-
$alias = $declaringMethod->name !== $method->name ? ' ' . $method->name : '';
-
if ($modifier || $alias) {
-
$resolutions[] = $declaringMethod->name . ' as' . $modifier . $alias;
-
}
-
}
-
-
$class->setMethods($methods);
-
-
foreach ($from->getTraitNames() as $trait) {
-
$trait = $class->addTrait($trait);
-
foreach ($resolutions as $resolution) {
-
$trait->addResolution($resolution);
-
}
-
$resolutions = [];
-
}
-
-
$consts = $cases = [];
-
foreach ($from->getReflectionConstants() as $const) {
-
if ($class->isEnum() && $from->hasCase($const->name)) {
-
$cases[] = $this->fromCaseReflection($const);
-
} elseif ($const->getDeclaringClass()->name === $from->name) {
-
$consts[] = $this->fromConstantReflection($const);
-
}
-
}
-
-
if ($consts) {
-
$class->setConstants($consts);
-
}
-
if ($cases) {
-
$class->setCases($cases);
-
}
-
-
return $class;
-
}
-
-
-
public function fromMethodReflection(\ReflectionMethod $from): Method
-
{
-
$method = new Method($from->name);
-
$method->setParameters(array_map([$this, 'fromParameterReflection'], $from->getParameters()));
-
$method->setStatic($from->isStatic());
-
$isInterface = $from->getDeclaringClass()->isInterface();
-
$method->setVisibility($isInterface ? null : $this->getVisibility($from));
-
$method->setFinal($from->isFinal());
-
$method->setAbstract($from->isAbstract() && !$isInterface);
-
$method->setReturnReference($from->returnsReference());
-
$method->setVariadic($from->isVariadic());
-
$method->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
-
$method->setAttributes($this->getAttributes($from));
-
$method->setReturnType((string) $from->getReturnType());
-
-
return $method;
-
}
-
-
-
public function fromFunctionReflection(\ReflectionFunction $from, bool $withBody = false): GlobalFunction|Closure
-
{
-
$function = $from->isClosure() ? new Closure : new GlobalFunction($from->name);
-
$function->setParameters(array_map([$this, 'fromParameterReflection'], $from->getParameters()));
-
$function->setReturnReference($from->returnsReference());
-
$function->setVariadic($from->isVariadic());
-
if (!$from->isClosure()) {
-
$function->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
-
}
-
-
$function->setAttributes($this->getAttributes($from));
-
$function->setReturnType((string) $from->getReturnType());
-
-
if ($withBody) {
-
if ($from->isClosure() || $from->isInternal()) {
-
throw new Nette\NotSupportedException('The $withBody parameter cannot be used for closures or internal functions.');
-
}
-
-
$function->setBody($this->getExtractor($from->getFileName())->extractFunctionBody($from->name));
-
}
-
-
return $function;
-
}
-
-
-
public function fromCallable(callable $from): Method|GlobalFunction|Closure
-
{
-
$ref = Nette\Utils\Callback::toReflection($from);
-
return $ref instanceof \ReflectionMethod
-
? $this->fromMethodReflection($ref)
-
: $this->fromFunctionReflection($ref);
-
}
-
-
-
public function fromParameterReflection(\ReflectionParameter $from): Parameter
-
{
-
if ($from->isPromoted()) {
-
$property = $from->getDeclaringClass()->getProperty($from->name);
-
$param = (new PromotedParameter($from->name))
-
->setVisibility($this->getVisibility($property))
-
->setReadOnly($property->isReadonly())
-
->setFinal(PHP_VERSION_ID >= 80500 && $property->isFinal() && !$property->isPrivateSet());
-
$this->addHooks($property, $param);
-
} else {
-
$param = new Parameter($from->name);
-
}
-
$param->setReference($from->isPassedByReference());
-
$param->setType((string) $from->getType());
-
-
if ($from->isDefaultValueAvailable()) {
-
if ($from->isDefaultValueConstant()) {
-
$parts = explode('::', $from->getDefaultValueConstantName());
-
if (count($parts) > 1) {
-
$parts[0] = Helpers::tagName($parts[0]);
-
}
-
-
$param->setDefaultValue(new Literal(implode('::', $parts)));
-
} elseif (is_object($from->getDefaultValue())) {
-
$param->setDefaultValue($this->fromObject($from->getDefaultValue()));
-
} else {
-
$param->setDefaultValue($from->getDefaultValue());
-
}
-
}
-
-
$param->setAttributes($this->getAttributes($from));
-
return $param;
-
}
-
-
-
public function fromConstantReflection(\ReflectionClassConstant $from): Constant
-
{
-
$const = new Constant($from->name);
-
$const->setValue($from->getValue());
-
$const->setVisibility($this->getVisibility($from));
-
$const->setFinal($from->isFinal());
-
$const->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
-
$const->setAttributes($this->getAttributes($from));
-
return $const;
-
}
-
-
-
public function fromCaseReflection(\ReflectionClassConstant $from): EnumCase
-
{
-
$const = new EnumCase($from->name);
-
$const->setValue($from->getValue()->value ?? null);
-
$const->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
-
$const->setAttributes($this->getAttributes($from));
-
return $const;
-
}
-
-
-
public function fromPropertyReflection(\ReflectionProperty $from): Property
-
{
-
$defaults = $from->getDeclaringClass()->getDefaultProperties();
-
$prop = new Property($from->name);
-
$prop->setValue($defaults[$prop->getName()] ?? null);
-
$prop->setStatic($from->isStatic());
-
$prop->setVisibility($this->getVisibility($from));
-
$prop->setType((string) $from->getType());
-
$prop->setInitialized($from->hasType() && array_key_exists($prop->getName(), $defaults));
-
$prop->setReadOnly($from->isReadOnly());
-
$prop->setComment(Helpers::unformatDocComment((string) $from->getDocComment()));
-
$prop->setAttributes($this->getAttributes($from));
-
-
if (PHP_VERSION_ID >= 80400) {
-
$this->addHooks($from, $prop);
-
$isInterface = $from->getDeclaringClass()->isInterface();
-
$prop->setFinal($from->isFinal() && !$prop->isPrivate(PropertyAccessMode::Set));
-
$prop->setAbstract($from->isAbstract() && !$isInterface);
-
}
-
return $prop;
-
}
-
-
-
private function addHooks(\ReflectionProperty $from, Property|PromotedParameter $prop): void
-
{
-
if (PHP_VERSION_ID < 80400) {
-
return;
-
}
-
-
$getV = $this->getVisibility($from);
-
$setV = $from->isPrivateSet()
-
? Visibility::Private
-
: ($from->isProtectedSet() ? Visibility::Protected : $getV);
-
$defaultSetV = $from->isReadOnly() && $getV !== Visibility::Private
-
? Visibility::Protected
-
: $getV;
-
if ($setV !== $defaultSetV) {
-
$prop->setVisibility($getV === Visibility::Public ? null : $getV, $setV);
-
}
-
-
foreach ($from->getHooks() as $type => $hook) {
-
$params = $hook->getParameters();
-
if (
-
count($params) === 1
-
&& $params[0]->getName() === 'value'
-
&& $params[0]->getType() == $from->getType() // intentionally ==
-
) {
-
$params = [];
-
}
-
$prop->addHook($type)
-
->setParameters(array_map([$this, 'fromParameterReflection'], $params))
-
->setAbstract($hook->isAbstract())
-
->setFinal($hook->isFinal())
-
->setReturnReference($hook->returnsReference())
-
->setComment(Helpers::unformatDocComment((string) $hook->getDocComment()))
-
->setAttributes($this->getAttributes($hook));
-
}
-
}
-
-
-
public function fromObject(object $obj): Literal
-
{
-
return new Literal('new \\' . $obj::class . '(/* unknown */)');
-
}
-
-
-
public function fromClassCode(string $code): ClassLike
-
{
-
$classes = $this->fromCode($code)->getClasses();
-
return reset($classes) ?: throw new Nette\InvalidStateException('The code does not contain any class.');
-
}
-
-
-
public function fromCode(string $code): PhpFile
-
{
-
$reader = new Extractor($code);
-
return $reader->extractAll();
-
}
-
-
-
/** @return Attribute[] */
-
private function getAttributes($from): array
-
{
-
return array_map(function ($attr) {
-
$args = $attr->getArguments();
-
foreach ($args as &$arg) {
-
if (is_object($arg)) {
-
$arg = $this->fromObject($arg);
-
}
-
}
-
-
return new Attribute($attr->getName(), $args);
-
}, $from->getAttributes());
-
}
-
-
-
private function getVisibility(\ReflectionProperty|\ReflectionMethod|\ReflectionClassConstant $from): Visibility
-
{
-
return $from->isPrivate()
-
? Visibility::Private
-
: ($from->isProtected() ? Visibility::Protected : Visibility::Public);
-
}
-
-
-
private function getExtractor(string $file): Extractor
-
{
-
$cache = &$this->extractorCache[$file];
-
$cache ??= new Extractor(file_get_contents($file));
-
return $cache;
-
}
-
}
-41
vendor/nette/php-generator/src/PhpGenerator/GlobalFunction.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
-
-
/**
-
* Definition of a global function.
-
*/
-
final class GlobalFunction
-
{
-
use Traits\FunctionLike;
-
use Traits\NameAware;
-
use Traits\CommentAware;
-
use Traits\AttributeAware;
-
-
public static function from(string|\Closure $function, bool $withBody = false): self
-
{
-
return (new Factory)->fromFunctionReflection(Nette\Utils\Callback::toReflection($function), $withBody);
-
}
-
-
-
public function __toString(): string
-
{
-
return (new Printer)->printFunction($this);
-
}
-
-
-
public function __clone(): void
-
{
-
$this->parameters = array_map(fn($param) => clone $param, $this->parameters);
-
}
-
}
-156
vendor/nette/php-generator/src/PhpGenerator/Helpers.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use function is_string, preg_match, preg_replace, preg_replace_callback, str_contains, str_repeat, str_replace, strrpos, strtolower, substr, trim;
-
-
-
/**
-
* @internal
-
*/
-
final class Helpers
-
{
-
use Nette\StaticClass;
-
-
public const ReIdentifier = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
-
-
public const Keywords = [
-
// class keywords
-
'bool' => 1, 'false' => 1, 'float' => 1, 'int' => 1, 'iterable' => 1, 'mixed' => 1, 'never' => 1, 'null' => 1,
-
'object' => 1, 'parent' => 1, 'self' => 1, 'string' => 1, 'true' => 1, 'void' => 1,
-
-
// PHP keywords
-
'__halt_compiler' => 1, 'abstract' => 1, 'and' => 1, 'array' => 1, 'as' => 1, 'break' => 1, 'callable' => 1,
-
'case' => 1, 'catch' => 1, 'class' => 1, 'clone' => 1, 'const' => 1, 'continue' => 1, 'declare' => 1, 'default' => 1,
-
'die' => 1, 'do' => 1, 'echo' => 1, 'else' => 1, 'elseif' => 1, 'empty' => 1, 'enddeclare' => 1, 'endfor' => 1,
-
'endforeach' => 1, 'endif' => 1, 'endswitch' => 1, 'endwhile' => 1, 'eval' => 1, 'exit' => 1, 'extends' => 1,
-
'final' => 1, 'finally' => 1, 'fn' => 1, 'for' => 1, 'foreach' => 1, 'function' => 1, 'global' => 1, 'goto' => 1,
-
'if' => 1, 'implements' => 1, 'include' => 1, 'include_once' => 1, 'instanceof' => 1, 'insteadof' => 1,
-
'interface' => 1, 'isset' => 1, 'list' => 1, 'match' => 1, 'namespace' => 1, 'new' => 1, 'or' => 1, 'print' => 1,
-
'private' => 1, 'protected' => 1, 'public' => 1, 'readonly' => 1, 'require' => 1, 'require_once' => 1, 'return' => 1,
-
'static' => 1, 'switch' => 1, 'throw' => 1, 'trait' => 1, 'try' => 1, 'unset' => 1, 'use' => 1, 'var' => 1,
-
'while' => 1, 'xor' => 1, 'yield' => 1, '__CLASS__' => 1, '__DIR__' => 1, '__FILE__' => 1, '__FUNCTION__' => 1,
-
'__LINE__' => 1, '__METHOD__' => 1, '__NAMESPACE__' => 1, '__PROPERTY__' => 1, '__TRAIT__' => 1,
-
];
-
-
#[\Deprecated]
-
public const
-
PHP_IDENT = self::ReIdentifier,
-
KEYWORDS = self::Keywords;
-
-
-
public static function formatDocComment(string $content, bool $forceMultiLine = false): string
-
{
-
$s = trim($content);
-
$s = str_replace('*/', '* /', $s);
-
if ($s === '') {
-
return '';
-
} elseif ($forceMultiLine || str_contains($content, "\n")) {
-
$s = str_replace("\n", "\n * ", "/**\n$s") . "\n */";
-
return Nette\Utils\Strings::normalize($s) . "\n";
-
} else {
-
return "/** $s */\n";
-
}
-
}
-
-
-
public static function tagName(string $name, string $of = PhpNamespace::NameNormal): string
-
{
-
return isset(self::Keywords[strtolower($name)])
-
? $name
-
: "/*($of*/$name";
-
}
-
-
-
public static function simplifyTaggedNames(string $code, ?PhpNamespace $namespace): string
-
{
-
return preg_replace_callback('~/\*\(([ncf])\*/([\w\x7f-\xff\\\]++)~', function ($m) use ($namespace) {
-
[, $of, $name] = $m;
-
return $namespace
-
? $namespace->simplifyType($name, $of)
-
: $name;
-
}, $code);
-
}
-
-
-
public static function unformatDocComment(string $comment): string
-
{
-
return preg_replace('#^\s*\* ?#m', '', trim(trim(trim($comment), '/*')));
-
}
-
-
-
public static function unindent(string $s, int $level = 1): string
-
{
-
return $level
-
? preg_replace('#^(\t| {4}){1,' . $level . '}#m', '', $s)
-
: $s;
-
}
-
-
-
public static function isIdentifier(mixed $value): bool
-
{
-
return is_string($value) && preg_match('#^' . self::ReIdentifier . '$#D', $value);
-
}
-
-
-
public static function isNamespaceIdentifier(mixed $value, bool $allowLeadingSlash = false): bool
-
{
-
$re = '#^' . ($allowLeadingSlash ? '\\\?' : '') . self::ReIdentifier . '(\\\\' . self::ReIdentifier . ')*$#D';
-
return is_string($value) && preg_match($re, $value);
-
}
-
-
-
public static function extractNamespace(string $name): string
-
{
-
return ($pos = strrpos($name, '\\')) ? substr($name, 0, $pos) : '';
-
}
-
-
-
public static function extractShortName(string $name): string
-
{
-
return ($pos = strrpos($name, '\\')) === false
-
? $name
-
: substr($name, $pos + 1);
-
}
-
-
-
public static function tabsToSpaces(string $s, int $count = 4): string
-
{
-
return str_replace("\t", str_repeat(' ', $count), $s);
-
}
-
-
-
/**
-
* @param mixed[] $props
-
* @internal
-
*/
-
public static function createObject(string $class, array $props): object
-
{
-
return Dumper::createObject($class, $props);
-
}
-
-
-
public static function validateType(?string $type, bool &$nullable = false): ?string
-
{
-
if ($type === '' || $type === null) {
-
return null;
-
} elseif (!Nette\Utils\Validators::isTypeDeclaration($type)) {
-
throw new Nette\InvalidArgumentException("Value '$type' is not valid type.");
-
}
-
-
if ($type[0] === '?') {
-
$nullable = true;
-
return substr($type, 1);
-
}
-
-
return $type;
-
}
-
}
-95
vendor/nette/php-generator/src/PhpGenerator/InterfaceType.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
-
-
/**
-
* Definition of an interface with properties, methods and constants.
-
*/
-
final class InterfaceType extends ClassLike
-
{
-
use Traits\ConstantsAware;
-
use Traits\MethodsAware;
-
use Traits\PropertiesAware;
-
-
/** @var string[] */
-
private array $extends = [];
-
-
-
/**
-
* @param string|string[] $names
-
*/
-
public function setExtends(string|array $names): static
-
{
-
$names = (array) $names;
-
$this->validateNames($names);
-
$this->extends = $names;
-
return $this;
-
}
-
-
-
/** @return string[] */
-
public function getExtends(): array
-
{
-
return $this->extends;
-
}
-
-
-
public function addExtend(string $name): static
-
{
-
$this->validateNames([$name]);
-
$this->extends[] = $name;
-
return $this;
-
}
-
-
-
/**
-
* Adds a member. If it already exists, throws an exception or overwrites it if $overwrite is true.
-
*/
-
public function addMember(Method|Constant|Property $member, bool $overwrite = false): static
-
{
-
$name = $member->getName();
-
[$type, $n] = match (true) {
-
$member instanceof Constant => ['consts', $name],
-
$member instanceof Method => ['methods', strtolower($name)],
-
$member instanceof Property => ['properties', $name],
-
};
-
if (!$overwrite && isset($this->$type[$n])) {
-
throw new Nette\InvalidStateException("Cannot add member '$name', because it already exists.");
-
}
-
$this->$type[$n] = $member;
-
return $this;
-
}
-
-
-
/** @throws Nette\InvalidStateException */
-
public function validate(): void
-
{
-
foreach ($this->getProperties() as $property) {
-
if ($property->isInitialized()) {
-
throw new Nette\InvalidStateException("Property {$this->getName()}::\${$property->getName()}: Interface cannot have initialized properties.");
-
} elseif (!$property->getHooks()) {
-
throw new Nette\InvalidStateException("Property {$this->getName()}::\${$property->getName()}: Interface cannot have properties without hooks.");
-
}
-
}
-
}
-
-
-
public function __clone(): void
-
{
-
parent::__clone();
-
$clone = fn($item) => clone $item;
-
$this->consts = array_map($clone, $this->consts);
-
$this->methods = array_map($clone, $this->methods);
-
$this->properties = array_map($clone, $this->properties);
-
}
-
}
-49
vendor/nette/php-generator/src/PhpGenerator/Literal.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
-
/**
-
* PHP literal value.
-
*/
-
class Literal
-
{
-
/**
-
* Creates a literal representing the creation of an object using the new operator.
-
* @param mixed[] $args
-
*/
-
public static function new(string $class, array $args = []): self
-
{
-
return new self('new ' . $class . '(...?:)', [$args]);
-
}
-
-
-
public function __construct(
-
private string $value,
-
/** @var ?mixed[] */
-
private ?array $args = null,
-
) {
-
}
-
-
-
public function __toString(): string
-
{
-
return $this->formatWith(new Dumper);
-
}
-
-
-
/** @internal */
-
public function formatWith(Dumper $dumper): string
-
{
-
return $this->args === null
-
? $this->value
-
: $dumper->format($this->value, ...$this->args);
-
}
-
}
-115
vendor/nette/php-generator/src/PhpGenerator/Method.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use function func_num_args;
-
-
-
/**
-
* Definition of a class method.
-
*/
-
final class Method
-
{
-
use Traits\FunctionLike;
-
use Traits\NameAware;
-
use Traits\VisibilityAware;
-
use Traits\CommentAware;
-
use Traits\AttributeAware;
-
-
public const Constructor = '__construct';
-
-
private bool $static = false;
-
private bool $final = false;
-
private bool $abstract = false;
-
-
-
/**
-
* @param string|array{object|string, string}|\Closure $method
-
*/
-
public static function from(string|array|\Closure $method): static
-
{
-
return (new Factory)->fromMethodReflection(Nette\Utils\Callback::toReflection($method));
-
}
-
-
-
public function __toString(): string
-
{
-
return (new Printer)->printMethod($this);
-
}
-
-
-
public function setStatic(bool $state = true): static
-
{
-
$this->static = $state;
-
return $this;
-
}
-
-
-
public function isStatic(): bool
-
{
-
return $this->static;
-
}
-
-
-
public function setFinal(bool $state = true): static
-
{
-
$this->final = $state;
-
return $this;
-
}
-
-
-
public function isFinal(): bool
-
{
-
return $this->final;
-
}
-
-
-
public function setAbstract(bool $state = true): static
-
{
-
$this->abstract = $state;
-
return $this;
-
}
-
-
-
public function isAbstract(): bool
-
{
-
return $this->abstract;
-
}
-
-
-
/**
-
* @param string $name without $
-
*/
-
public function addPromotedParameter(string $name, mixed $defaultValue = null): PromotedParameter
-
{
-
$param = new PromotedParameter($name);
-
if (func_num_args() > 1) {
-
$param->setDefaultValue($defaultValue);
-
}
-
-
return $this->parameters[$name] = $param;
-
}
-
-
-
/** @throws Nette\InvalidStateException */
-
public function validate(): void
-
{
-
if ($this->abstract && ($this->final || $this->visibility === Visibility::Private)) {
-
throw new Nette\InvalidStateException("Method $this->name() cannot be abstract and final or private at the same time.");
-
}
-
}
-
-
-
public function __clone(): void
-
{
-
$this->parameters = array_map(fn($param) => clone $param, $this->parameters);
-
}
-
}
-96
vendor/nette/php-generator/src/PhpGenerator/Parameter.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette\Utils\Type;
-
-
-
/**
-
* Definition of a function/method parameter.
-
*/
-
class Parameter
-
{
-
use Traits\NameAware;
-
use Traits\AttributeAware;
-
use Traits\CommentAware;
-
-
private bool $reference = false;
-
private ?string $type = null;
-
private bool $nullable = false;
-
private bool $hasDefaultValue = false;
-
private mixed $defaultValue = null;
-
-
-
public function setReference(bool $state = true): static
-
{
-
$this->reference = $state;
-
return $this;
-
}
-
-
-
public function isReference(): bool
-
{
-
return $this->reference;
-
}
-
-
-
public function setType(?string $type): static
-
{
-
$this->type = Helpers::validateType($type, $this->nullable);
-
return $this;
-
}
-
-
-
/** @return ($asObject is true ? ?Type : ?string) */
-
public function getType(bool $asObject = false): Type|string|null
-
{
-
return $asObject && $this->type
-
? Type::fromString($this->type)
-
: $this->type;
-
}
-
-
-
public function setNullable(bool $state = true): static
-
{
-
$this->nullable = $state;
-
return $this;
-
}
-
-
-
public function isNullable(): bool
-
{
-
return $this->nullable || ($this->hasDefaultValue && $this->defaultValue === null);
-
}
-
-
-
public function setDefaultValue(mixed $val): static
-
{
-
$this->defaultValue = $val;
-
$this->hasDefaultValue = true;
-
return $this;
-
}
-
-
-
public function getDefaultValue(): mixed
-
{
-
return $this->defaultValue;
-
}
-
-
-
public function hasDefaultValue(): bool
-
{
-
return $this->hasDefaultValue;
-
}
-
-
-
public function validate(): void
-
{
-
}
-
}
-193
vendor/nette/php-generator/src/PhpGenerator/PhpFile.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use function count;
-
-
-
/**
-
* Definition of a PHP file.
-
*
-
* Generates:
-
* - opening tag (<?php)
-
* - doc comments
-
* - one or more namespaces
-
*/
-
final class PhpFile
-
{
-
use Traits\CommentAware;
-
-
/** @var PhpNamespace[] */
-
private array $namespaces = [];
-
private bool $strictTypes = false;
-
-
-
public static function fromCode(string $code): self
-
{
-
return (new Factory)->fromCode($code);
-
}
-
-
-
/**
-
* Adds a class to the file. If it already exists, throws an exception.
-
* As a parameter, pass the full name with namespace.
-
*/
-
public function addClass(string $name): ClassType
-
{
-
return $this
-
->addNamespace(Helpers::extractNamespace($name))
-
->addClass(Helpers::extractShortName($name));
-
}
-
-
-
/**
-
* Adds an interface to the file. If it already exists, throws an exception.
-
* As a parameter, pass the full name with namespace.
-
*/
-
public function addInterface(string $name): InterfaceType
-
{
-
return $this
-
->addNamespace(Helpers::extractNamespace($name))
-
->addInterface(Helpers::extractShortName($name));
-
}
-
-
-
/**
-
* Adds a trait to the file. If it already exists, throws an exception.
-
* As a parameter, pass the full name with namespace.
-
*/
-
public function addTrait(string $name): TraitType
-
{
-
return $this
-
->addNamespace(Helpers::extractNamespace($name))
-
->addTrait(Helpers::extractShortName($name));
-
}
-
-
-
/**
-
* Adds an enum to the file. If it already exists, throws an exception.
-
* As a parameter, pass the full name with namespace.
-
*/
-
public function addEnum(string $name): EnumType
-
{
-
return $this
-
->addNamespace(Helpers::extractNamespace($name))
-
->addEnum(Helpers::extractShortName($name));
-
}
-
-
-
/**
-
* Adds a function to the file. If it already exists, throws an exception.
-
* As a parameter, pass the full name with namespace.
-
*/
-
public function addFunction(string $name): GlobalFunction
-
{
-
return $this
-
->addNamespace(Helpers::extractNamespace($name))
-
->addFunction(Helpers::extractShortName($name));
-
}
-
-
-
/**
-
* Adds a namespace to the file. If it already exists, it returns the existing one.
-
*/
-
public function addNamespace(string|PhpNamespace $namespace): PhpNamespace
-
{
-
$res = $namespace instanceof PhpNamespace
-
? ($this->namespaces[$namespace->getName()] = $namespace)
-
: ($this->namespaces[$namespace] ??= new PhpNamespace($namespace));
-
-
foreach ($this->namespaces as $namespace) {
-
$namespace->setBracketedSyntax(count($this->namespaces) > 1 && isset($this->namespaces['']));
-
}
-
-
return $res;
-
}
-
-
-
/**
-
* Removes the namespace from the file.
-
*/
-
public function removeNamespace(string|PhpNamespace $namespace): static
-
{
-
$name = $namespace instanceof PhpNamespace ? $namespace->getName() : $namespace;
-
unset($this->namespaces[$name]);
-
return $this;
-
}
-
-
-
/** @return PhpNamespace[] */
-
public function getNamespaces(): array
-
{
-
return $this->namespaces;
-
}
-
-
-
/** @return (ClassType|InterfaceType|TraitType|EnumType)[] */
-
public function getClasses(): array
-
{
-
$classes = [];
-
foreach ($this->namespaces as $n => $namespace) {
-
$n .= $n ? '\\' : '';
-
foreach ($namespace->getClasses() as $c => $class) {
-
$classes[$n . $c] = $class;
-
}
-
}
-
-
return $classes;
-
}
-
-
-
/** @return GlobalFunction[] */
-
public function getFunctions(): array
-
{
-
$functions = [];
-
foreach ($this->namespaces as $n => $namespace) {
-
$n .= $n ? '\\' : '';
-
foreach ($namespace->getFunctions() as $f => $function) {
-
$functions[$n . $f] = $function;
-
}
-
}
-
-
return $functions;
-
}
-
-
-
/**
-
* Adds a use statement to the file, to the global namespace.
-
*/
-
public function addUse(string $name, ?string $alias = null, string $of = PhpNamespace::NameNormal): static
-
{
-
$this->addNamespace('')->addUse($name, $alias, $of);
-
return $this;
-
}
-
-
-
/**
-
* Adds declare(strict_types=1) to output.
-
*/
-
public function setStrictTypes(bool $state = true): static
-
{
-
$this->strictTypes = $state;
-
return $this;
-
}
-
-
-
public function hasStrictTypes(): bool
-
{
-
return $this->strictTypes;
-
}
-
-
-
public function __toString(): string
-
{
-
return (new Printer)->printFile($this);
-
}
-
}
-16
vendor/nette/php-generator/src/PhpGenerator/PhpLiteral.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
-
/** @deprecated use Nette\PhpGenerator\Literal */
-
class PhpLiteral extends Literal
-
{
-
}
-412
vendor/nette/php-generator/src/PhpGenerator/PhpNamespace.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use Nette\InvalidStateException;
-
use function strlen;
-
use const ARRAY_FILTER_USE_BOTH;
-
-
-
/**
-
* Definition of a PHP namespace.
-
*
-
* Generates:
-
* - namespace statement
-
* - variable amount of use statements
-
* - one or more class declarations
-
*/
-
final class PhpNamespace
-
{
-
public const
-
NameNormal = 'n',
-
NameFunction = 'f',
-
NameConstant = 'c';
-
-
#[\Deprecated('use PhpNamespace::NameNormal')]
-
public const NAME_NORMAL = self::NameNormal;
-
-
#[\Deprecated('use PhpNamespace::NameFunction')]
-
public const NAME_FUNCTION = self::NameFunction;
-
-
#[\Deprecated('use PhpNamespace::NameConstant')]
-
public const NAME_CONSTANT = self::NameConstant;
-
-
private string $name;
-
-
private bool $bracketedSyntax = false;
-
-
/** @var string[][] */
-
private array $aliases = [
-
self::NameNormal => [],
-
self::NameFunction => [],
-
self::NameConstant => [],
-
];
-
-
/** @var (ClassType|InterfaceType|TraitType|EnumType)[] */
-
private array $classes = [];
-
-
/** @var GlobalFunction[] */
-
private array $functions = [];
-
-
-
public function __construct(string $name)
-
{
-
if ($name !== '' && !Helpers::isNamespaceIdentifier($name)) {
-
throw new Nette\InvalidArgumentException("Value '$name' is not valid name.");
-
}
-
-
$this->name = $name;
-
}
-
-
-
public function getName(): string
-
{
-
return $this->name;
-
}
-
-
-
/**
-
* @internal
-
*/
-
public function setBracketedSyntax(bool $state = true): static
-
{
-
$this->bracketedSyntax = $state;
-
return $this;
-
}
-
-
-
public function hasBracketedSyntax(): bool
-
{
-
return $this->bracketedSyntax;
-
}
-
-
-
/**
-
* Adds a use statement to the namespace for class, function or constant.
-
* @throws InvalidStateException
-
*/
-
public function addUse(string $name, ?string $alias = null, string $of = self::NameNormal): static
-
{
-
if (
-
!Helpers::isNamespaceIdentifier($name, allowLeadingSlash: true)
-
|| (Helpers::isIdentifier($name) && isset(Helpers::Keywords[strtolower($name)]))
-
) {
-
throw new Nette\InvalidArgumentException("Value '$name' is not valid class/function/constant name.");
-
-
} elseif ($alias && (!Helpers::isIdentifier($alias) || isset(Helpers::Keywords[strtolower($alias)]))) {
-
throw new Nette\InvalidArgumentException("Value '$alias' is not valid alias.");
-
}
-
-
$name = ltrim($name, '\\');
-
$aliases = array_change_key_case($this->aliases[$of]);
-
$used = [self::NameNormal => $this->classes, self::NameFunction => $this->functions, self::NameConstant => []][$of];
-
-
if ($alias === null) {
-
$base = Helpers::extractShortName($name);
-
$counter = null;
-
do {
-
$alias = $base . $counter;
-
$lower = strtolower($alias);
-
$counter++;
-
} while ((isset($aliases[$lower]) && strcasecmp($aliases[$lower], $name) !== 0) || isset($used[$lower]));
-
} else {
-
$lower = strtolower($alias);
-
if (isset($aliases[$lower]) && strcasecmp($aliases[$lower], $name) !== 0) {
-
throw new InvalidStateException(
-
"Alias '$alias' used already for '{$aliases[$lower]}', cannot use for '$name'.",
-
);
-
} elseif (isset($used[$lower])) {
-
throw new Nette\InvalidStateException("Name '$alias' used already for '$this->name\\{$used[$lower]->getName()}'.");
-
}
-
}
-
-
$this->aliases[$of][$alias] = $name;
-
return $this;
-
}
-
-
-
public function removeUse(string $name, string $of = self::NameNormal): void
-
{
-
foreach ($this->aliases[$of] as $alias => $item) {
-
if (strcasecmp($item, $name) === 0) {
-
unset($this->aliases[$of][$alias]);
-
}
-
}
-
}
-
-
-
/**
-
* Adds a use statement to the namespace for function.
-
*/
-
public function addUseFunction(string $name, ?string $alias = null): static
-
{
-
return $this->addUse($name, $alias, self::NameFunction);
-
}
-
-
-
/**
-
* Adds a use statement to the namespace for constant.
-
*/
-
public function addUseConstant(string $name, ?string $alias = null): static
-
{
-
return $this->addUse($name, $alias, self::NameConstant);
-
}
-
-
-
/** @return string[] */
-
public function getUses(string $of = self::NameNormal): array
-
{
-
uasort($this->aliases[$of], fn(string $a, string $b): int => strtr($a, '\\', ' ') <=> strtr($b, '\\', ' '));
-
return array_filter(
-
$this->aliases[$of],
-
fn($name, $alias) => (bool) strcasecmp(($this->name ? $this->name . '\\' : '') . $alias, $name),
-
ARRAY_FILTER_USE_BOTH,
-
);
-
}
-
-
-
/**
-
* Resolves relative name to full name.
-
*/
-
public function resolveName(string $name, string $of = self::NameNormal): string
-
{
-
if (isset(Helpers::Keywords[strtolower($name)]) || $name === '') {
-
return $name;
-
} elseif ($name[0] === '\\') {
-
return substr($name, 1);
-
}
-
-
$aliases = array_change_key_case($this->aliases[$of]);
-
if ($of !== self::NameNormal) {
-
return $aliases[strtolower($name)]
-
?? $this->resolveName(Helpers::extractNamespace($name) . '\\') . Helpers::extractShortName($name);
-
}
-
-
$parts = explode('\\', $name, 2);
-
return ($res = $aliases[strtolower($parts[0])] ?? null)
-
? $res . (isset($parts[1]) ? '\\' . $parts[1] : '')
-
: $this->name . ($this->name ? '\\' : '') . $name;
-
}
-
-
-
/**
-
* Simplifies type hint with relative names.
-
*/
-
public function simplifyType(string $type, string $of = self::NameNormal): string
-
{
-
return preg_replace_callback('~[\w\x7f-\xff\\\]+~', fn($m) => $this->simplifyName($m[0], $of), $type);
-
}
-
-
-
/**
-
* Simplifies the full name of a class, function, or constant to a relative name.
-
*/
-
public function simplifyName(string $name, string $of = self::NameNormal): string
-
{
-
if (isset(Helpers::Keywords[strtolower($name)]) || $name === '') {
-
return $name;
-
}
-
-
$name = ltrim($name, '\\');
-
-
if ($of !== self::NameNormal) {
-
foreach ($this->aliases[$of] as $alias => $original) {
-
if (strcasecmp($original, $name) === 0) {
-
return $alias;
-
}
-
}
-
-
return $this->simplifyName(Helpers::extractNamespace($name) . '\\') . Helpers::extractShortName($name);
-
}
-
-
$shortest = null;
-
$relative = self::startsWith($name, $this->name . '\\')
-
? substr($name, strlen($this->name) + 1)
-
: null;
-
-
foreach ($this->aliases[$of] as $alias => $original) {
-
if ($relative && self::startsWith($relative . '\\', $alias . '\\')) {
-
$relative = null;
-
}
-
-
if (self::startsWith($name . '\\', $original . '\\')) {
-
$short = $alias . substr($name, strlen($original));
-
if (!isset($shortest) || strlen($shortest) > strlen($short)) {
-
$shortest = $short;
-
}
-
}
-
}
-
-
if (isset($shortest, $relative) && strlen($shortest) < strlen($relative)) {
-
return $shortest;
-
}
-
-
return $relative ?? $shortest ?? ($this->name ? '\\' : '') . $name;
-
}
-
-
-
/**
-
* Adds a class-like type to the namespace. If it already exists, throws an exception.
-
*/
-
public function add(ClassType|InterfaceType|TraitType|EnumType $class): static
-
{
-
$name = $class->getName();
-
if ($name === null) {
-
throw new Nette\InvalidArgumentException('Class does not have a name.');
-
}
-
-
$lower = strtolower($name);
-
if (isset($this->classes[$lower]) && $this->classes[$lower] !== $class) {
-
throw new Nette\InvalidStateException("Cannot add '$name', because it already exists.");
-
} elseif ($orig = array_change_key_case($this->aliases[self::NameNormal])[$lower] ?? null) {
-
throw new Nette\InvalidStateException("Name '$name' used already as alias for $orig.");
-
}
-
-
$this->classes[$lower] = $class;
-
return $this;
-
}
-
-
-
/**
-
* Adds a class to the namespace. If it already exists, throws an exception.
-
*/
-
public function addClass(string $name): ClassType
-
{
-
$this->add($class = new ClassType($name, $this));
-
return $class;
-
}
-
-
-
/**
-
* Adds an interface to the namespace. If it already exists, throws an exception.
-
*/
-
public function addInterface(string $name): InterfaceType
-
{
-
$this->add($iface = new InterfaceType($name, $this));
-
return $iface;
-
}
-
-
-
/**
-
* Adds a trait to the namespace. If it already exists, throws an exception.
-
*/
-
public function addTrait(string $name): TraitType
-
{
-
$this->add($trait = new TraitType($name, $this));
-
return $trait;
-
}
-
-
-
/**
-
* Adds an enum to the namespace. If it already exists, throws an exception.
-
*/
-
public function addEnum(string $name): EnumType
-
{
-
$this->add($enum = new EnumType($name, $this));
-
return $enum;
-
}
-
-
-
/**
-
* Returns a class-like type from the namespace.
-
*/
-
public function getClass(string $name): ClassType|InterfaceType|TraitType|EnumType
-
{
-
return $this->classes[strtolower($name)] ?? throw new Nette\InvalidArgumentException("Class '$name' not found.");
-
}
-
-
-
/**
-
* Returns all class-like types in the namespace.
-
* @return (ClassType|InterfaceType|TraitType|EnumType)[]
-
*/
-
public function getClasses(): array
-
{
-
$res = [];
-
foreach ($this->classes as $class) {
-
$res[$class->getName()] = $class;
-
}
-
-
return $res;
-
}
-
-
-
/**
-
* Removes a class-like type from namespace.
-
*/
-
public function removeClass(string $name): static
-
{
-
unset($this->classes[strtolower($name)]);
-
return $this;
-
}
-
-
-
/**
-
* Adds a function to the namespace. If it already exists, throws an exception.
-
*/
-
public function addFunction(string $name): GlobalFunction
-
{
-
$lower = strtolower($name);
-
if (isset($this->functions[$lower])) {
-
throw new Nette\InvalidStateException("Cannot add '$name', because it already exists.");
-
} elseif ($orig = array_change_key_case($this->aliases[self::NameFunction])[$lower] ?? null) {
-
throw new Nette\InvalidStateException("Name '$name' used already as alias for $orig.");
-
}
-
-
return $this->functions[$lower] = new GlobalFunction($name);
-
}
-
-
-
/**
-
* Returns a function from the namespace.
-
*/
-
public function getFunction(string $name): GlobalFunction
-
{
-
return $this->functions[strtolower($name)] ?? throw new Nette\InvalidArgumentException("Function '$name' not found.");
-
}
-
-
-
/**
-
* Returns all functions in the namespace.
-
* @return GlobalFunction[]
-
*/
-
public function getFunctions(): array
-
{
-
$res = [];
-
foreach ($this->functions as $fn) {
-
$res[$fn->getName()] = $fn;
-
}
-
-
return $res;
-
}
-
-
-
/**
-
* Removes a function type from namespace.
-
*/
-
public function removeFunction(string $name): static
-
{
-
unset($this->functions[strtolower($name)]);
-
return $this;
-
}
-
-
-
private static function startsWith(string $a, string $b): bool
-
{
-
return strncasecmp($a, $b, strlen($b)) === 0;
-
}
-
-
-
public function __toString(): string
-
{
-
return (new Printer)->printNamespace($this);
-
}
-
}
-543
vendor/nette/php-generator/src/PhpGenerator/Printer.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use Nette\Utils\Strings;
-
use function array_filter, array_map, count, end, get_debug_type, implode, is_scalar, ltrim, preg_replace, rtrim, str_contains, str_repeat, str_replace, strlen, substr;
-
-
-
/**
-
* Generates PHP code.
-
*/
-
class Printer
-
{
-
public int $wrapLength = 120;
-
public string $indentation = "\t";
-
public int $linesBetweenProperties = 0;
-
public int $linesBetweenMethods = 2;
-
public int $linesBetweenUseTypes = 0;
-
public string $returnTypeColon = ': ';
-
public bool $bracesOnNextLine = true;
-
public bool $singleParameterOnOneLine = false;
-
public bool $omitEmptyNamespaces = true;
-
protected ?PhpNamespace $namespace = null;
-
protected ?Dumper $dumper;
-
private bool $resolveTypes = true;
-
-
-
public function __construct()
-
{
-
$this->dumper = new Dumper;
-
}
-
-
-
public function printFunction(GlobalFunction $function, ?PhpNamespace $namespace = null): string
-
{
-
$this->namespace = $this->resolveTypes ? $namespace : null;
-
$line = 'function '
-
. ($function->getReturnReference() ? '&' : '')
-
. $function->getName();
-
$returnType = $this->printReturnType($function);
-
$params = $this->printParameters($function, strlen($line) + strlen($returnType) + 2); // 2 = parentheses
-
$body = $this->printFunctionBody($function);
-
$braceOnNextLine = $this->isBraceOnNextLine(str_contains($params, "\n"), (bool) $returnType);
-
-
return $this->printDocComment($function)
-
. $this->printAttributes($function->getAttributes())
-
. $line
-
. $params
-
. $returnType
-
. ($braceOnNextLine ? "\n" : ' ')
-
. "{\n" . $this->indent($body) . "}\n";
-
}
-
-
-
public function printClosure(Closure $closure, ?PhpNamespace $namespace = null): string
-
{
-
$this->namespace = $this->resolveTypes ? $namespace : null;
-
$uses = [];
-
foreach ($closure->getUses() as $param) {
-
$uses[] = ($param->isReference() ? '&' : '') . '$' . $param->getName();
-
}
-
-
$useStr = strlen($tmp = implode(', ', $uses)) > $this->wrapLength && count($uses) > 1
-
? "\n" . $this->indentation . implode(",\n" . $this->indentation, $uses) . ",\n"
-
: $tmp;
-
$body = $this->printFunctionBody($closure);
-
-
return $this->printAttributes($closure->getAttributes(), inline: true)
-
. 'function '
-
. ($closure->getReturnReference() ? '&' : '')
-
. $this->printParameters($closure)
-
. ($uses ? " use ($useStr)" : '')
-
. $this->printReturnType($closure)
-
. " {\n" . $this->indent($body) . '}';
-
}
-
-
-
public function printArrowFunction(Closure $closure, ?PhpNamespace $namespace = null): string
-
{
-
$this->namespace = $this->resolveTypes ? $namespace : null;
-
foreach ($closure->getUses() as $use) {
-
if ($use->isReference()) {
-
throw new Nette\InvalidArgumentException('Arrow function cannot bind variables by-reference.');
-
}
-
}
-
-
$body = $this->printFunctionBody($closure);
-
-
return $this->printAttributes($closure->getAttributes())
-
. 'fn'
-
. ($closure->getReturnReference() ? '&' : '')
-
. $this->printParameters($closure)
-
. $this->printReturnType($closure)
-
. ' => ' . rtrim($body, "\n") . ';';
-
}
-
-
-
public function printMethod(Method $method, ?PhpNamespace $namespace = null, bool $isInterface = false): string
-
{
-
$this->namespace = $this->resolveTypes ? $namespace : null;
-
$method->validate();
-
$line = ($method->isAbstract() && !$isInterface ? 'abstract ' : '')
-
. ($method->isFinal() ? 'final ' : '')
-
. ($method->getVisibility() ? $method->getVisibility() . ' ' : '')
-
. ($method->isStatic() ? 'static ' : '')
-
. 'function '
-
. ($method->getReturnReference() ? '&' : '')
-
. $method->getName();
-
$returnType = $this->printReturnType($method);
-
$params = $this->printParameters($method, strlen($line) + strlen($returnType) + strlen($this->indentation) + 2);
-
$body = $this->printFunctionBody($method);
-
$braceOnNextLine = $this->isBraceOnNextLine(str_contains($params, "\n"), (bool) $returnType);
-
-
return $this->printDocComment($method)
-
. $this->printAttributes($method->getAttributes())
-
. $line
-
. $params
-
. $returnType
-
. ($method->isAbstract() || $isInterface
-
? ";\n"
-
: ($braceOnNextLine ? "\n" : ' ') . "{\n" . $this->indent($body) . "}\n");
-
}
-
-
-
private function printFunctionBody(Closure|GlobalFunction|Method|PropertyHook $function): string
-
{
-
$code = Helpers::simplifyTaggedNames($function->getBody(), $this->namespace);
-
$code = Strings::normalize($code);
-
return ltrim(rtrim($code) . "\n");
-
}
-
-
-
public function printClass(
-
ClassType|InterfaceType|TraitType|EnumType $class,
-
?PhpNamespace $namespace = null,
-
): string
-
{
-
$this->namespace = $this->resolveTypes ? $namespace : null;
-
$class->validate();
-
$resolver = $this->namespace
-
? [$namespace, 'simplifyType']
-
: fn($s) => $s;
-
-
$traits = [];
-
if ($class instanceof ClassType || $class instanceof TraitType || $class instanceof EnumType) {
-
foreach ($class->getTraits() as $trait) {
-
$resolutions = implode(";\n", $trait->getResolutions());
-
$resolutions = Helpers::simplifyTaggedNames($resolutions, $this->namespace);
-
$traits[] = $this->printDocComment($trait)
-
. 'use ' . $resolver($trait->getName())
-
. ($resolutions
-
? " {\n" . $this->indent($resolutions) . ";\n}\n"
-
: ";\n");
-
}
-
}
-
-
$cases = [];
-
$enumType = null;
-
if ($class instanceof EnumType) {
-
$enumType = $class->getType();
-
foreach ($class->getCases() as $case) {
-
$enumType ??= is_scalar($case->getValue()) ? get_debug_type($case->getValue()) : null;
-
$cases[] = $this->printDocComment($case)
-
. $this->printAttributes($case->getAttributes())
-
. 'case ' . $case->getName()
-
. ($case->getValue() === null ? '' : ' = ' . $this->dump($case->getValue()))
-
. ";\n";
-
}
-
}
-
-
$readOnlyClass = $class instanceof ClassType && $class->isReadOnly();
-
$consts = [];
-
$methods = [];
-
if (
-
$class instanceof ClassType
-
|| $class instanceof InterfaceType
-
|| $class instanceof TraitType
-
|| $class instanceof EnumType
-
) {
-
foreach ($class->getConstants() as $const) {
-
$consts[] = $this->printConstant($const);
-
}
-
-
foreach ($class->getMethods() as $method) {
-
if ($readOnlyClass && $method->getName() === Method::Constructor) {
-
$method = clone $method;
-
array_map(fn($param) => $param instanceof PromotedParameter ? $param->setReadOnly(false) : null, $method->getParameters());
-
}
-
$methods[] = $this->printMethod($method, $namespace, $class->isInterface());
-
}
-
}
-
-
$properties = [];
-
if ($class instanceof ClassType || $class instanceof TraitType || $class instanceof InterfaceType) {
-
foreach ($class->getProperties() as $property) {
-
$properties[] = $this->printProperty($property, $readOnlyClass, $class instanceof InterfaceType);
-
}
-
}
-
-
$members = array_filter([
-
implode('', $traits),
-
$this->joinProperties($consts),
-
$this->joinProperties($cases),
-
$this->joinProperties($properties),
-
($methods && $properties ? str_repeat("\n", $this->linesBetweenMethods - 1) : '')
-
. implode(str_repeat("\n", $this->linesBetweenMethods), $methods),
-
]);
-
-
if ($class instanceof ClassType) {
-
$line[] = $class->isAbstract() ? 'abstract' : null;
-
$line[] = $class->isFinal() ? 'final' : null;
-
$line[] = $class->isReadOnly() ? 'readonly' : null;
-
}
-
-
$line[] = match (true) {
-
$class instanceof ClassType => $class->getName() ? 'class ' . $class->getName() : null,
-
$class instanceof InterfaceType => 'interface ' . $class->getName(),
-
$class instanceof TraitType => 'trait ' . $class->getName(),
-
$class instanceof EnumType => 'enum ' . $class->getName() . ($enumType ? $this->returnTypeColon . $enumType : ''),
-
};
-
$line[] = ($class instanceof ClassType || $class instanceof InterfaceType) && $class->getExtends()
-
? 'extends ' . implode(', ', array_map($resolver, (array) $class->getExtends()))
-
: null;
-
$line[] = ($class instanceof ClassType || $class instanceof EnumType) && $class->getImplements()
-
? 'implements ' . implode(', ', array_map($resolver, $class->getImplements()))
-
: null;
-
$line[] = $class->getName() ? null : '{';
-
-
return $this->printDocComment($class)
-
. $this->printAttributes($class->getAttributes())
-
. implode(' ', array_filter($line))
-
. ($class->getName() ? "\n{\n" : "\n")
-
. ($members ? $this->indent(implode("\n", $members)) : '')
-
. '}'
-
. ($class->getName() ? "\n" : '');
-
}
-
-
-
public function printNamespace(PhpNamespace $namespace): string
-
{
-
$this->namespace = $this->resolveTypes ? $namespace : null;
-
$name = $namespace->getName();
-
$uses = [
-
$this->printUses($namespace),
-
$this->printUses($namespace, PhpNamespace::NameFunction),
-
$this->printUses($namespace, PhpNamespace::NameConstant),
-
];
-
$uses = implode(str_repeat("\n", $this->linesBetweenUseTypes), array_filter($uses));
-
-
$items = [];
-
foreach ($namespace->getClasses() as $class) {
-
$items[] = $this->printClass($class, $namespace);
-
}
-
-
foreach ($namespace->getFunctions() as $function) {
-
$items[] = $this->printFunction($function, $namespace);
-
}
-
-
$body = ($uses ? $uses . "\n" : '')
-
. implode("\n", $items);
-
-
if ($namespace->hasBracketedSyntax()) {
-
return 'namespace' . ($name ? " $name" : '') . "\n{\n"
-
. $this->indent($body)
-
. "}\n";
-
-
} else {
-
return ($name ? "namespace $name;\n\n" : '')
-
. $body;
-
}
-
}
-
-
-
public function printFile(PhpFile $file): string
-
{
-
$namespaces = [];
-
foreach ($file->getNamespaces() as $namespace) {
-
if (!$this->omitEmptyNamespaces || $namespace->getClasses() || $namespace->getFunctions()) {
-
$namespaces[] = $this->printNamespace($namespace);
-
}
-
}
-
-
return "<?php\n"
-
. ($file->getComment() ? "\n" . $this->printDocComment($file) : '')
-
. "\n"
-
. ($file->hasStrictTypes() ? "declare(strict_types=1);\n\n" : '')
-
. implode("\n\n", $namespaces);
-
}
-
-
-
protected function printUses(PhpNamespace $namespace, string $of = PhpNamespace::NameNormal): string
-
{
-
$prefix = [
-
PhpNamespace::NameNormal => '',
-
PhpNamespace::NameFunction => 'function ',
-
PhpNamespace::NameConstant => 'const ',
-
][$of];
-
$uses = [];
-
foreach ($namespace->getUses($of) as $alias => $original) {
-
$uses[] = Helpers::extractShortName($original) === $alias
-
? "use $prefix$original;\n"
-
: "use $prefix$original as $alias;\n";
-
}
-
-
return implode('', $uses);
-
}
-
-
-
protected function printParameters(Closure|GlobalFunction|Method|PropertyHook $function, int $column = 0): string
-
{
-
$special = false;
-
foreach ($function->getParameters() as $param) {
-
$param->validate();
-
$special = $special || $param instanceof PromotedParameter || $param->getAttributes() || $param->getComment();
-
}
-
-
if (!$special || ($this->singleParameterOnOneLine && count($function->getParameters()) === 1)) {
-
$line = $this->formatParameters($function, multiline: false);
-
if (!str_contains($line, "\n") && strlen($line) + $column <= $this->wrapLength) {
-
return $line;
-
}
-
}
-
-
return $this->formatParameters($function, multiline: true);
-
}
-
-
-
private function formatParameters(Closure|GlobalFunction|Method|PropertyHook $function, bool $multiline): string
-
{
-
$params = $function->getParameters();
-
$res = '';
-
-
foreach ($params as $param) {
-
$variadic = !$function instanceof PropertyHook && $function->isVariadic() && $param === end($params);
-
$attrs = $this->printAttributes($param->getAttributes(), inline: true);
-
$res .=
-
$this->printDocComment($param)
-
. ($attrs ? ($multiline ? substr($attrs, 0, -1) . "\n" : $attrs) : '')
-
. ($param instanceof PromotedParameter
-
? ($param->isFinal() ? 'final ' : '')
-
. $this->printPropertyVisibility($param)
-
. ($param->isReadOnly() && $param->getType() ? ' readonly' : '')
-
. ' '
-
: '')
-
. ltrim($this->printType($param->getType(), $param->isNullable()) . ' ')
-
. ($param->isReference() ? '&' : '')
-
. ($variadic ? '...' : '')
-
. '$' . $param->getName()
-
. ($param->hasDefaultValue() && !$variadic ? ' = ' . $this->dump($param->getDefaultValue()) : '')
-
. ($param instanceof PromotedParameter ? $this->printHooks($param) : '')
-
. ($multiline ? ",\n" : ', ');
-
}
-
-
return $multiline
-
? "(\n" . $this->indent($res) . ')'
-
: '(' . substr($res, 0, -2) . ')';
-
}
-
-
-
private function printConstant(Constant $const): string
-
{
-
$def = ($const->isFinal() ? 'final ' : '')
-
. ($const->getVisibility() ? $const->getVisibility() . ' ' : '')
-
. 'const '
-
. ltrim($this->printType($const->getType(), nullable: false) . ' ')
-
. $const->getName() . ' = ';
-
-
return $this->printDocComment($const)
-
. $this->printAttributes($const->getAttributes())
-
. $def
-
. $this->dump($const->getValue(), strlen($def)) . ";\n";
-
}
-
-
-
private function printProperty(Property $property, bool $readOnlyClass = false, bool $isInterface = false): string
-
{
-
$property->validate();
-
$type = $property->getType();
-
$def = ($property->isAbstract() && !$isInterface ? 'abstract ' : '')
-
. ($property->isFinal() ? 'final ' : '')
-
. $this->printPropertyVisibility($property)
-
. ($property->isStatic() ? ' static' : '')
-
. (!$readOnlyClass && $property->isReadOnly() && $type ? ' readonly' : '')
-
. ' '
-
. ltrim($this->printType($type, $property->isNullable()) . ' ')
-
. '$' . $property->getName();
-
-
$defaultValue = $property->getValue() === null && !$property->isInitialized()
-
? ''
-
: ' = ' . $this->dump($property->getValue(), strlen($def) + 3); // 3 = ' = '
-
-
return $this->printDocComment($property)
-
. $this->printAttributes($property->getAttributes())
-
. $def
-
. $defaultValue
-
. ($this->printHooks($property, $isInterface) ?: ';')
-
. "\n";
-
}
-
-
-
private function printPropertyVisibility(Property|PromotedParameter $param): string
-
{
-
$get = $param->getVisibility(PropertyAccessMode::Get);
-
$set = $param->getVisibility(PropertyAccessMode::Set);
-
return $set
-
? ($get ? "$get $set(set)" : "$set(set)")
-
: $get ?? 'public';
-
}
-
-
-
protected function printType(?string $type, bool $nullable): string
-
{
-
if ($type === null) {
-
return '';
-
}
-
-
if ($this->namespace) {
-
$type = $this->namespace->simplifyType($type);
-
}
-
-
return $nullable
-
? Type::nullable($type)
-
: $type;
-
}
-
-
-
protected function printDocComment(/*Traits\CommentAware*/ $commentable): string
-
{
-
$multiLine = $commentable instanceof GlobalFunction
-
|| $commentable instanceof Method
-
|| $commentable instanceof ClassLike
-
|| $commentable instanceof PhpFile;
-
return Helpers::formatDocComment((string) $commentable->getComment(), $multiLine);
-
}
-
-
-
protected function printReturnType(Closure|GlobalFunction|Method $function): string
-
{
-
return ($tmp = $this->printType($function->getReturnType(), $function->isReturnNullable()))
-
? $this->returnTypeColon . $tmp
-
: '';
-
}
-
-
-
/** @param Attribute[] $attrs */
-
protected function printAttributes(array $attrs, bool $inline = false): string
-
{
-
if (!$attrs) {
-
return '';
-
}
-
-
$this->dumper->indentation = $this->indentation;
-
$items = [];
-
foreach ($attrs as $attr) {
-
$args = $this->dumper->format('...?:', $attr->getArguments());
-
$args = Helpers::simplifyTaggedNames($args, $this->namespace);
-
$items[] = $this->printType($attr->getName(), nullable: false) . ($args === '' ? '' : "($args)");
-
$inline = $inline && !str_contains($args, "\n");
-
}
-
-
return $inline
-
? '#[' . implode(', ', $items) . '] '
-
: '#[' . implode("]\n#[", $items) . "]\n";
-
}
-
-
-
private function printHooks(Property|PromotedParameter $property, bool $isInterface = false): string
-
{
-
$hooks = $property->getHooks();
-
if (!$hooks) {
-
return '';
-
}
-
-
$simple = true;
-
foreach ($hooks as $type => $hook) {
-
$simple = $simple && ($hook->isAbstract() || $isInterface);
-
$hooks[$type] = $this->printDocComment($hook)
-
. $this->printAttributes($hook->getAttributes())
-
. ($hook->isAbstract() || $isInterface
-
? ($hook->getReturnReference() ? '&' : '')
-
. $type . ';'
-
: ($hook->isFinal() ? 'final ' : '')
-
. ($hook->getReturnReference() ? '&' : '')
-
. $type
-
. ($hook->getParameters() ? $this->printParameters($hook) : '')
-
. ' '
-
. ($hook->isShort()
-
? '=> ' . $hook->getBody() . ';'
-
: "{\n" . $this->indent($this->printFunctionBody($hook)) . '}'));
-
}
-
-
return $simple
-
? ' { ' . implode(' ', $hooks) . ' }'
-
: " {\n" . $this->indent(implode("\n", $hooks)) . "\n}";
-
}
-
-
-
public function setTypeResolving(bool $state = true): static
-
{
-
$this->resolveTypes = $state;
-
return $this;
-
}
-
-
-
protected function indent(string $s): string
-
{
-
$s = str_replace("\t", $this->indentation, $s);
-
return Strings::indent($s, 1, $this->indentation);
-
}
-
-
-
protected function dump(mixed $var, int $column = 0): string
-
{
-
$this->dumper->indentation = $this->indentation;
-
$this->dumper->wrapLength = $this->wrapLength;
-
$s = $this->dumper->dump($var, $column);
-
$s = Helpers::simplifyTaggedNames($s, $this->namespace);
-
return $s;
-
}
-
-
-
/** @param string[] $props */
-
private function joinProperties(array $props): string
-
{
-
return $this->linesBetweenProperties
-
? implode(str_repeat("\n", $this->linesBetweenProperties), $props)
-
: preg_replace('#^(\w.*\n)\n(?=\w.*;)#m', '$1', implode("\n", $props));
-
}
-
-
-
protected function isBraceOnNextLine(bool $multiLine, bool $hasReturnType): bool
-
{
-
return $this->bracesOnNextLine && (!$multiLine || $hasReturnType);
-
}
-
}
-35
vendor/nette/php-generator/src/PhpGenerator/PromotedParameter.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
-
-
/**
-
* Definition of a promoted constructor parameter.
-
*/
-
final class PromotedParameter extends Parameter
-
{
-
use Traits\PropertyLike;
-
-
/** @throws Nette\InvalidStateException */
-
public function validate(): void
-
{
-
if ($this->readOnly && !$this->getType()) {
-
throw new Nette\InvalidStateException("Property \${$this->getName()}: Read-only properties are only supported on typed property.");
-
}
-
}
-
-
-
public function __clone(): void
-
{
-
$this->hooks = array_map(fn($item) => $item ? clone $item : $item, $this->hooks);
-
}
-
}
-138
vendor/nette/php-generator/src/PhpGenerator/Property.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use Nette\Utils\Type;
-
-
-
/**
-
* Definition of a class property.
-
*/
-
final class Property
-
{
-
use Traits\NameAware;
-
use Traits\PropertyLike;
-
use Traits\CommentAware;
-
use Traits\AttributeAware;
-
-
private mixed $value = null;
-
private bool $static = false;
-
private ?string $type = null;
-
private bool $nullable = false;
-
private bool $initialized = false;
-
private bool $abstract = false;
-
-
-
public function setValue(mixed $val): static
-
{
-
$this->value = $val;
-
$this->initialized = true;
-
return $this;
-
}
-
-
-
public function &getValue(): mixed
-
{
-
return $this->value;
-
}
-
-
-
public function setStatic(bool $state = true): static
-
{
-
$this->static = $state;
-
return $this;
-
}
-
-
-
public function isStatic(): bool
-
{
-
return $this->static;
-
}
-
-
-
public function setType(?string $type): static
-
{
-
$this->type = Helpers::validateType($type, $this->nullable);
-
return $this;
-
}
-
-
-
/** @return ($asObject is true ? ?Type : ?string) */
-
public function getType(bool $asObject = false): Type|string|null
-
{
-
return $asObject && $this->type
-
? Type::fromString($this->type)
-
: $this->type;
-
}
-
-
-
public function setNullable(bool $state = true): static
-
{
-
$this->nullable = $state;
-
return $this;
-
}
-
-
-
public function isNullable(): bool
-
{
-
return $this->nullable || ($this->initialized && $this->value === null);
-
}
-
-
-
public function setInitialized(bool $state = true): static
-
{
-
$this->initialized = $state;
-
return $this;
-
}
-
-
-
public function isInitialized(): bool
-
{
-
return $this->initialized || $this->value !== null;
-
}
-
-
-
public function setAbstract(bool $state = true): static
-
{
-
$this->abstract = $state;
-
return $this;
-
}
-
-
-
public function isAbstract(): bool
-
{
-
return $this->abstract;
-
}
-
-
-
/** @throws Nette\InvalidStateException */
-
public function validate(): void
-
{
-
if ($this->readOnly && !$this->type) {
-
throw new Nette\InvalidStateException("Property \$$this->name: Read-only properties are only supported on typed property.");
-
-
} elseif ($this->abstract && $this->final) {
-
throw new Nette\InvalidStateException("Property \$$this->name cannot be abstract and final at the same time.");
-
-
} elseif (
-
$this->abstract
-
&& !Nette\Utils\Arrays::some($this->getHooks(), fn($hook) => $hook->isAbstract())
-
) {
-
throw new Nette\InvalidStateException("Property \$$this->name: Abstract property must have at least one abstract hook.");
-
}
-
}
-
-
-
public function __clone(): void
-
{
-
$this->hooks = array_map(fn($item) => $item ? clone $item : $item, $this->hooks);
-
}
-
}
-20
vendor/nette/php-generator/src/PhpGenerator/PropertyAccessMode.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
-
/**
-
* Property access mode.
-
*/
-
enum PropertyAccessMode: string
-
{
-
case Set = 'set';
-
case Get = 'get';
-
}
-129
vendor/nette/php-generator/src/PhpGenerator/PropertyHook.php
···
-
<?php
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use JetBrains\PhpStorm\Language;
-
-
-
/**
-
* Definition of a property hook.
-
*/
-
final class PropertyHook
-
{
-
use Traits\AttributeAware;
-
use Traits\CommentAware;
-
-
private string $body = '';
-
private bool $short = false;
-
private bool $final = false;
-
private bool $abstract = false;
-
-
/** @var Parameter[] */
-
private array $parameters = [];
-
private bool $returnReference = false;
-
-
-
/** @param ?mixed[] $args */
-
public function setBody(
-
#[Language('PHP')]
-
string $code,
-
?array $args = null,
-
bool $short = false,
-
): static
-
{
-
$this->body = $args === null
-
? $code
-
: (new Dumper)->format($code, ...$args);
-
$this->short = $short;
-
return $this;
-
}
-
-
-
public function getBody(): string
-
{
-
return $this->body;
-
}
-
-
-
public function isShort(): bool
-
{
-
return $this->short && trim($this->body) !== '';
-
}
-
-
-
public function setFinal(bool $state = true): static
-
{
-
$this->final = $state;
-
return $this;
-
}
-
-
-
public function isFinal(): bool
-
{
-
return $this->final;
-
}
-
-
-
public function setAbstract(bool $state = true): static
-
{
-
$this->abstract = $state;
-
return $this;
-
}
-
-
-
public function isAbstract(): bool
-
{
-
return $this->abstract;
-
}
-
-
-
/**
-
* @param Parameter[] $val
-
* @internal
-
*/
-
public function setParameters(array $val): static
-
{
-
(function (Parameter ...$val) {})(...$val);
-
$this->parameters = [];
-
foreach ($val as $v) {
-
$this->parameters[$v->getName()] = $v;
-
}
-
-
return $this;
-
}
-
-
-
/**
-
* @return Parameter[]
-
* @internal
-
*/
-
public function getParameters(): array
-
{
-
return $this->parameters;
-
}
-
-
-
/**
-
* Adds a parameter. If it already exists, it overwrites it.
-
* @param string $name without $
-
*/
-
public function addParameter(string $name): Parameter
-
{
-
return $this->parameters[$name] = new Parameter($name);
-
}
-
-
-
public function setReturnReference(bool $state = true): static
-
{
-
$this->returnReference = $state;
-
return $this;
-
}
-
-
-
public function getReturnReference(): bool
-
{
-
return $this->returnReference;
-
}
-
}
-20
vendor/nette/php-generator/src/PhpGenerator/PropertyHookType.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
-
/**
-
* Property hook type.
-
*/
-
enum PropertyHookType: string
-
{
-
case Set = 'set';
-
case Get = 'get';
-
}
-27
vendor/nette/php-generator/src/PhpGenerator/PsrPrinter.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
-
/**
-
* Generates PHP code compatible with PSR-2 and PSR-12.
-
*/
-
class PsrPrinter extends Printer
-
{
-
public string $indentation = ' ';
-
public int $linesBetweenMethods = 1;
-
public int $linesBetweenUseTypes = 1;
-
-
-
protected function isBraceOnNextLine(bool $multiLine, bool $hasReturnType): bool
-
{
-
return !$multiLine;
-
}
-
}
-54
vendor/nette/php-generator/src/PhpGenerator/TraitType.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
-
-
/**
-
* Definition of a trait with properties, methods, constants and traits.
-
*/
-
final class TraitType extends ClassLike
-
{
-
use Traits\ConstantsAware;
-
use Traits\MethodsAware;
-
use Traits\PropertiesAware;
-
use Traits\TraitsAware;
-
-
/**
-
* Adds a member. If it already exists, throws an exception or overwrites it if $overwrite is true.
-
*/
-
public function addMember(Method|Property|Constant|TraitUse $member, bool $overwrite = false): static
-
{
-
$name = $member->getName();
-
[$type, $n] = match (true) {
-
$member instanceof Constant => ['consts', $name],
-
$member instanceof Method => ['methods', strtolower($name)],
-
$member instanceof Property => ['properties', $name],
-
$member instanceof TraitUse => ['traits', $name],
-
};
-
if (!$overwrite && isset($this->$type[$n])) {
-
throw new Nette\InvalidStateException("Cannot add member '$name', because it already exists.");
-
}
-
$this->$type[$n] = $member;
-
return $this;
-
}
-
-
-
public function __clone(): void
-
{
-
parent::__clone();
-
$clone = fn($item) => clone $item;
-
$this->consts = array_map($clone, $this->consts);
-
$this->methods = array_map($clone, $this->methods);
-
$this->properties = array_map($clone, $this->properties);
-
$this->traits = array_map($clone, $this->traits);
-
}
-
}
-49
vendor/nette/php-generator/src/PhpGenerator/TraitUse.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
-
-
/**
-
* Definition of a trait use statement.
-
*/
-
final class TraitUse
-
{
-
use Traits\NameAware;
-
use Traits\CommentAware;
-
-
/** @var string[] */
-
private array $resolutions = [];
-
-
-
public function __construct(string $name)
-
{
-
if (!Nette\PhpGenerator\Helpers::isNamespaceIdentifier($name, allowLeadingSlash: true)) {
-
throw new Nette\InvalidArgumentException("Value '$name' is not valid trait name.");
-
}
-
-
$this->name = $name;
-
}
-
-
-
public function addResolution(string $resolution): static
-
{
-
$this->resolutions[] = $resolution;
-
return $this;
-
}
-
-
-
/** @return string[] */
-
public function getResolutions(): array
-
{
-
return $this->resolutions;
-
}
-
}
-49
vendor/nette/php-generator/src/PhpGenerator/Traits/AttributeAware.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
use Nette\PhpGenerator\Attribute;
-
-
-
/**
-
* @internal
-
*/
-
trait AttributeAware
-
{
-
/** @var Attribute[] */
-
private array $attributes = [];
-
-
-
/** @param mixed[] $args */
-
public function addAttribute(string $name, array $args = []): static
-
{
-
$this->attributes[] = new Attribute($name, $args);
-
return $this;
-
}
-
-
-
/**
-
* Replaces all attributes.
-
* @param Attribute[] $attrs
-
*/
-
public function setAttributes(array $attrs): static
-
{
-
(function (Attribute ...$attrs) {})(...$attrs);
-
$this->attributes = $attrs;
-
return $this;
-
}
-
-
-
/** @return Attribute[] */
-
public function getAttributes(): array
-
{
-
return $this->attributes;
-
}
-
}
-49
vendor/nette/php-generator/src/PhpGenerator/Traits/CommentAware.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
-
/**
-
* @internal
-
*/
-
trait CommentAware
-
{
-
private ?string $comment = null;
-
-
-
public function setComment(?string $val): static
-
{
-
$this->comment = $val;
-
return $this;
-
}
-
-
-
public function getComment(): ?string
-
{
-
return $this->comment;
-
}
-
-
-
/**
-
* Adds a new line to the comment.
-
*/
-
public function addComment(string $val): static
-
{
-
$this->comment .= $this->comment ? "\n$val" : $val;
-
return $this;
-
}
-
-
-
public function removeComment(): static
-
{
-
$this->comment = null;
-
return $this;
-
}
-
}
-79
vendor/nette/php-generator/src/PhpGenerator/Traits/ConstantsAware.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
use Nette;
-
use Nette\PhpGenerator\Constant;
-
-
-
/**
-
* @internal
-
*/
-
trait ConstantsAware
-
{
-
/** @var array<string, Constant> */
-
private array $consts = [];
-
-
-
/**
-
* Replaces all constants.
-
* @param Constant[] $consts
-
*/
-
public function setConstants(array $consts): static
-
{
-
(function (Constant ...$consts) {})(...$consts);
-
$this->consts = [];
-
foreach ($consts as $const) {
-
$this->consts[$const->getName()] = $const;
-
}
-
-
return $this;
-
}
-
-
-
/** @return Constant[] */
-
public function getConstants(): array
-
{
-
return $this->consts;
-
}
-
-
-
public function getConstant(string $name): Constant
-
{
-
return $this->consts[$name] ?? throw new Nette\InvalidArgumentException("Constant '$name' not found.");
-
}
-
-
-
/**
-
* Adds a constant. If it already exists, throws an exception or overwrites it if $overwrite is true.
-
*/
-
public function addConstant(string $name, mixed $value, bool $overwrite = false): Constant
-
{
-
if (!$overwrite && isset($this->consts[$name])) {
-
throw new Nette\InvalidStateException("Cannot add constant '$name', because it already exists.");
-
}
-
return $this->consts[$name] = (new Constant($name))
-
->setValue($value)
-
->setPublic();
-
}
-
-
-
public function removeConstant(string $name): static
-
{
-
unset($this->consts[$name]);
-
return $this;
-
}
-
-
-
public function hasConstant(string $name): bool
-
{
-
return isset($this->consts[$name]);
-
}
-
}
-179
vendor/nette/php-generator/src/PhpGenerator/Traits/FunctionLike.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
use JetBrains\PhpStorm\Language;
-
use Nette;
-
use Nette\PhpGenerator\Dumper;
-
use Nette\PhpGenerator\Parameter;
-
use Nette\Utils\Type;
-
use function func_num_args;
-
-
-
/**
-
* @internal
-
*/
-
trait FunctionLike
-
{
-
private string $body = '';
-
-
/** @var Parameter[] */
-
private array $parameters = [];
-
private bool $variadic = false;
-
private ?string $returnType = null;
-
private bool $returnReference = false;
-
private bool $returnNullable = false;
-
-
-
/** @param ?mixed[] $args */
-
public function setBody(
-
#[Language('PHP')]
-
string $code,
-
?array $args = null,
-
): static
-
{
-
$this->body = $args === null
-
? $code
-
: (new Dumper)->format($code, ...$args);
-
return $this;
-
}
-
-
-
public function getBody(): string
-
{
-
return $this->body;
-
}
-
-
-
/** @param ?mixed[] $args */
-
public function addBody(
-
#[Language('PHP')]
-
string $code,
-
?array $args = null,
-
): static
-
{
-
$this->body .= ($args === null ? $code : (new Dumper)->format($code, ...$args)) . "\n";
-
return $this;
-
}
-
-
-
/**
-
* @param Parameter[] $val
-
*/
-
public function setParameters(array $val): static
-
{
-
(function (Parameter ...$val) {})(...$val);
-
$this->parameters = [];
-
foreach ($val as $v) {
-
$this->parameters[$v->getName()] = $v;
-
}
-
-
return $this;
-
}
-
-
-
/** @return Parameter[] */
-
public function getParameters(): array
-
{
-
return $this->parameters;
-
}
-
-
-
public function getParameter(string $name): Parameter
-
{
-
return $this->parameters[$name] ?? throw new Nette\InvalidArgumentException("Parameter '$name' not found.");
-
}
-
-
-
/**
-
* Adds a parameter. If it already exists, it overwrites it.
-
* @param string $name without $
-
*/
-
public function addParameter(string $name, mixed $defaultValue = null): Parameter
-
{
-
$param = new Parameter($name);
-
if (func_num_args() > 1) {
-
$param->setDefaultValue($defaultValue);
-
}
-
-
return $this->parameters[$name] = $param;
-
}
-
-
-
/**
-
* @param string $name without $
-
*/
-
public function removeParameter(string $name): static
-
{
-
unset($this->parameters[$name]);
-
return $this;
-
}
-
-
-
public function hasParameter(string $name): bool
-
{
-
return isset($this->parameters[$name]);
-
}
-
-
-
public function setVariadic(bool $state = true): static
-
{
-
$this->variadic = $state;
-
return $this;
-
}
-
-
-
public function isVariadic(): bool
-
{
-
return $this->variadic;
-
}
-
-
-
public function setReturnType(?string $type): static
-
{
-
$this->returnType = Nette\PhpGenerator\Helpers::validateType($type, $this->returnNullable);
-
return $this;
-
}
-
-
-
/** @return ($asObject is true ? ?Type : ?string) */
-
public function getReturnType(bool $asObject = false): Type|string|null
-
{
-
return $asObject && $this->returnType
-
? Type::fromString($this->returnType)
-
: $this->returnType;
-
}
-
-
-
public function setReturnReference(bool $state = true): static
-
{
-
$this->returnReference = $state;
-
return $this;
-
}
-
-
-
public function getReturnReference(): bool
-
{
-
return $this->returnReference;
-
}
-
-
-
public function setReturnNullable(bool $state = true): static
-
{
-
$this->returnNullable = $state;
-
return $this;
-
}
-
-
-
public function isReturnNullable(): bool
-
{
-
return $this->returnNullable;
-
}
-
}
-89
vendor/nette/php-generator/src/PhpGenerator/Traits/MethodsAware.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
use Nette;
-
use Nette\PhpGenerator\Method;
-
use function strtolower;
-
-
-
/**
-
* @internal
-
*/
-
trait MethodsAware
-
{
-
/** @var array<string, Method> */
-
private array $methods = [];
-
-
-
/**
-
* Replaces all methods.
-
* @param Method[] $methods
-
*/
-
public function setMethods(array $methods): static
-
{
-
(function (Method ...$methods) {})(...$methods);
-
$this->methods = [];
-
foreach ($methods as $m) {
-
$this->methods[strtolower($m->getName())] = $m;
-
}
-
-
return $this;
-
}
-
-
-
/** @return Method[] */
-
public function getMethods(): array
-
{
-
$res = [];
-
foreach ($this->methods as $m) {
-
$res[$m->getName()] = $m;
-
}
-
-
return $res;
-
}
-
-
-
public function getMethod(string $name): Method
-
{
-
return $this->methods[strtolower($name)] ?? throw new Nette\InvalidArgumentException("Method '$name' not found.");
-
}
-
-
-
/**
-
* Adds a method. If it already exists, throws an exception or overwrites it if $overwrite is true.
-
*/
-
public function addMethod(string $name, bool $overwrite = false): Method
-
{
-
$lower = strtolower($name);
-
if (!$overwrite && isset($this->methods[$lower])) {
-
throw new Nette\InvalidStateException("Cannot add method '$name', because it already exists.");
-
}
-
$method = new Method($name);
-
if (!$this->isInterface()) {
-
$method->setPublic();
-
}
-
-
return $this->methods[$lower] = $method;
-
}
-
-
-
public function removeMethod(string $name): static
-
{
-
unset($this->methods[strtolower($name)]);
-
return $this;
-
}
-
-
-
public function hasMethod(string $name): bool
-
{
-
return isset($this->methods[strtolower($name)]);
-
}
-
}
-48
vendor/nette/php-generator/src/PhpGenerator/Traits/NameAware.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
use Nette;
-
-
-
/**
-
* @internal
-
*/
-
trait NameAware
-
{
-
private string $name;
-
-
-
public function __construct(string $name)
-
{
-
if (!Nette\PhpGenerator\Helpers::isIdentifier($name)) {
-
throw new Nette\InvalidArgumentException("Value '$name' is not valid name.");
-
}
-
-
$this->name = $name;
-
}
-
-
-
public function getName(): string
-
{
-
return $this->name;
-
}
-
-
-
/**
-
* Returns clone with a different name.
-
*/
-
public function cloneWithName(string $name): static
-
{
-
$dolly = clone $this;
-
$dolly->__construct($name);
-
return $dolly;
-
}
-
}
-82
vendor/nette/php-generator/src/PhpGenerator/Traits/PropertiesAware.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
use Nette;
-
use Nette\PhpGenerator\Property;
-
use function func_num_args;
-
-
-
/**
-
* @internal
-
*/
-
trait PropertiesAware
-
{
-
/** @var array<string, Property> */
-
private array $properties = [];
-
-
-
/**
-
* Replaces all properties.
-
* @param Property[] $props
-
*/
-
public function setProperties(array $props): static
-
{
-
(function (Property ...$props) {})(...$props);
-
$this->properties = [];
-
foreach ($props as $v) {
-
$this->properties[$v->getName()] = $v;
-
}
-
-
return $this;
-
}
-
-
-
/** @return Property[] */
-
public function getProperties(): array
-
{
-
return $this->properties;
-
}
-
-
-
public function getProperty(string $name): Property
-
{
-
return $this->properties[$name] ?? throw new Nette\InvalidArgumentException("Property '$name' not found.");
-
}
-
-
-
/**
-
* Adds a property. If it already exists, throws an exception or overwrites it if $overwrite is true.
-
* @param string $name without $
-
*/
-
public function addProperty(string $name, mixed $value = null, bool $overwrite = false): Property
-
{
-
if (!$overwrite && isset($this->properties[$name])) {
-
throw new Nette\InvalidStateException("Cannot add property '$name', because it already exists.");
-
}
-
return $this->properties[$name] = func_num_args() > 1
-
? (new Property($name))->setValue($value)
-
: new Property($name);
-
}
-
-
-
/** @param string $name without $ */
-
public function removeProperty(string $name): static
-
{
-
unset($this->properties[$name]);
-
return $this;
-
}
-
-
-
public function hasProperty(string $name): bool
-
{
-
return isset($this->properties[$name]);
-
}
-
}
-160
vendor/nette/php-generator/src/PhpGenerator/Traits/PropertyLike.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
use Nette\PhpGenerator\PropertyAccessMode;
-
use Nette\PhpGenerator\PropertyHook;
-
use Nette\PhpGenerator\PropertyHookType;
-
use Nette\PhpGenerator\Visibility;
-
use function array_filter, in_array, is_string;
-
-
-
/**
-
* @internal
-
*/
-
trait PropertyLike
-
{
-
/** @var array{set: ?Visibility, get: ?Visibility} */
-
private array $visibility = ['set' => null, 'get' => null];
-
private bool $final = false;
-
private bool $readOnly = false;
-
-
/** @var array<string, ?PropertyHook> */
-
private array $hooks = ['set' => null, 'get' => null];
-
-
-
public function setVisibility(Visibility|string|null $get, Visibility|string|null $set = null): static
-
{
-
$this->visibility = [
-
'set' => $set instanceof Visibility || $set === null ? $set : Visibility::from($set),
-
'get' => $get instanceof Visibility || $get === null ? $get : Visibility::from($get),
-
];
-
return $this;
-
}
-
-
-
public function getVisibility(PropertyAccessMode|string $mode = PropertyAccessMode::Get): ?string
-
{
-
$mode = is_string($mode) ? PropertyAccessMode::from($mode) : $mode;
-
return $this->visibility[$mode->value]?->value;
-
}
-
-
-
public function setPublic(PropertyAccessMode|string $mode = PropertyAccessMode::Get): static
-
{
-
$mode = is_string($mode) ? PropertyAccessMode::from($mode) : $mode;
-
$this->visibility[$mode->value] = Visibility::Public;
-
return $this;
-
}
-
-
-
public function isPublic(PropertyAccessMode|string $mode = PropertyAccessMode::Get): bool
-
{
-
$mode = is_string($mode) ? PropertyAccessMode::from($mode) : $mode;
-
return in_array($this->visibility[$mode->value], [Visibility::Public, null], true);
-
}
-
-
-
public function setProtected(PropertyAccessMode|string $mode = PropertyAccessMode::Get): static
-
{
-
$mode = is_string($mode) ? PropertyAccessMode::from($mode) : $mode;
-
$this->visibility[$mode->value] = Visibility::Protected;
-
return $this;
-
}
-
-
-
public function isProtected(PropertyAccessMode|string $mode = PropertyAccessMode::Get): bool
-
{
-
$mode = is_string($mode) ? PropertyAccessMode::from($mode) : $mode;
-
return $this->visibility[$mode->value] === Visibility::Protected;
-
}
-
-
-
public function setPrivate(PropertyAccessMode|string $mode = PropertyAccessMode::Get): static
-
{
-
$mode = is_string($mode) ? PropertyAccessMode::from($mode) : $mode;
-
$this->visibility[$mode->value] = Visibility::Private;
-
return $this;
-
}
-
-
-
public function isPrivate(PropertyAccessMode|string $mode = PropertyAccessMode::Get): bool
-
{
-
$mode = is_string($mode) ? PropertyAccessMode::from($mode) : $mode;
-
return $this->visibility[$mode->value] === Visibility::Private;
-
}
-
-
-
public function setFinal(bool $state = true): static
-
{
-
$this->final = $state;
-
return $this;
-
}
-
-
-
public function isFinal(): bool
-
{
-
return $this->final;
-
}
-
-
-
public function setReadOnly(bool $state = true): static
-
{
-
$this->readOnly = $state;
-
return $this;
-
}
-
-
-
public function isReadOnly(): bool
-
{
-
return $this->readOnly;
-
}
-
-
-
/**
-
* Replaces all hooks.
-
* @param PropertyHook[] $hooks
-
*/
-
public function setHooks(array $hooks): static
-
{
-
(function (PropertyHook ...$hooks) {})(...$hooks);
-
$this->hooks = $hooks;
-
return $this;
-
}
-
-
-
/** @return array<string, PropertyHook> */
-
public function getHooks(): array
-
{
-
return array_filter($this->hooks);
-
}
-
-
-
public function addHook(PropertyHookType|string $type, string $shortBody = ''): PropertyHook
-
{
-
$type = is_string($type) ? PropertyHookType::from($type) : $type;
-
return $this->hooks[$type->value] = (new PropertyHook)
-
->setBody($shortBody, short: true);
-
}
-
-
-
public function getHook(PropertyHookType|string $type): ?PropertyHook
-
{
-
$type = is_string($type) ? PropertyHookType::from($type) : $type;
-
return $this->hooks[$type->value] ?? null;
-
}
-
-
-
public function hasHook(PropertyHookType|string $type): bool
-
{
-
$type = is_string($type) ? PropertyHookType::from($type) : $type;
-
return isset($this->hooks[$type->value]);
-
}
-
}
-78
vendor/nette/php-generator/src/PhpGenerator/Traits/TraitsAware.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
use Nette;
-
use Nette\PhpGenerator\TraitUse;
-
use function array_map, func_get_arg, func_num_args, is_array;
-
-
-
/**
-
* @internal
-
*/
-
trait TraitsAware
-
{
-
/** @var array<string, TraitUse> */
-
private array $traits = [];
-
-
-
/**
-
* Replaces all traits.
-
* @param TraitUse[] $traits
-
*/
-
public function setTraits(array $traits): static
-
{
-
(function (TraitUse ...$traits) {})(...$traits);
-
$this->traits = [];
-
foreach ($traits as $trait) {
-
$this->traits[$trait->getName()] = $trait;
-
}
-
-
return $this;
-
}
-
-
-
/** @return TraitUse[] */
-
public function getTraits(): array
-
{
-
return $this->traits;
-
}
-
-
-
/**
-
* Adds a method. If it already exists, throws an exception.
-
*/
-
public function addTrait(string $name): TraitUse
-
{
-
if (isset($this->traits[$name])) {
-
throw new Nette\InvalidStateException("Cannot add trait '$name', because it already exists.");
-
}
-
$this->traits[$name] = $trait = new TraitUse($name);
-
if (func_num_args() > 1 && is_array(func_get_arg(1))) { // back compatibility
-
trigger_error('Passing second argument to ' . __METHOD__ . '() is deprecated, use addResolution() instead.');
-
array_map(fn($item) => $trait->addResolution($item), func_get_arg(1));
-
}
-
-
return $trait;
-
}
-
-
-
public function removeTrait(string $name): static
-
{
-
unset($this->traits[$name]);
-
return $this;
-
}
-
-
-
public function hasTrait(string $name): bool
-
{
-
return isset($this->traits[$name]);
-
}
-
}
-75
vendor/nette/php-generator/src/PhpGenerator/Traits/VisibilityAware.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator\Traits;
-
-
use Nette\PhpGenerator\Visibility;
-
-
-
/**
-
* @internal
-
*/
-
trait VisibilityAware
-
{
-
private ?Visibility $visibility = null;
-
-
-
public function setVisibility(Visibility|string|null $value): static
-
{
-
$this->visibility = $value instanceof Visibility || $value === null
-
? $value
-
: Visibility::from($value);
-
return $this;
-
}
-
-
-
public function getVisibility(): ?string
-
{
-
return $this->visibility?->value;
-
}
-
-
-
public function setPublic(): static
-
{
-
$this->visibility = Visibility::Public;
-
return $this;
-
}
-
-
-
public function isPublic(): bool
-
{
-
return $this->visibility === Visibility::Public || $this->visibility === null;
-
}
-
-
-
public function setProtected(): static
-
{
-
$this->visibility = Visibility::Protected;
-
return $this;
-
}
-
-
-
public function isProtected(): bool
-
{
-
return $this->visibility === Visibility::Protected;
-
}
-
-
-
public function setPrivate(): static
-
{
-
$this->visibility = Visibility::Private;
-
return $this;
-
}
-
-
-
public function isPrivate(): bool
-
{
-
return $this->visibility === Visibility::Private;
-
}
-
}
-123
vendor/nette/php-generator/src/PhpGenerator/Type.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
use Nette;
-
use function implode, preg_match, preg_replace, str_contains;
-
-
-
/**
-
* PHP return, property and parameter types.
-
*/
-
class Type
-
{
-
public const
-
String = 'string',
-
Int = 'int',
-
Float = 'float',
-
Bool = 'bool',
-
Array = 'array',
-
Object = 'object',
-
Callable = 'callable',
-
Iterable = 'iterable',
-
Void = 'void',
-
Never = 'never',
-
Mixed = 'mixed',
-
True = 'true',
-
False = 'false',
-
Null = 'null',
-
Self = 'self',
-
Parent = 'parent',
-
Static = 'static';
-
-
#[\Deprecated('use Type::String')]
-
public const STRING = self::String;
-
-
#[\Deprecated('use Type::Int')]
-
public const INT = self::Int;
-
-
#[\Deprecated('use Type::Float')]
-
public const FLOAT = self::Float;
-
-
#[\Deprecated('use Type::Bool')]
-
public const BOOL = self::Bool;
-
-
#[\Deprecated('use Type::Array')]
-
public const ARRAY = self::Array;
-
-
#[\Deprecated('use Type::Object')]
-
public const OBJECT = self::Object;
-
-
#[\Deprecated('use Type::Callable')]
-
public const CALLABLE = self::Callable;
-
-
#[\Deprecated('use Type::Iterable')]
-
public const ITERABLE = self::Iterable;
-
-
#[\Deprecated('use Type::Void')]
-
public const VOID = self::Void;
-
-
#[\Deprecated('use Type::Never')]
-
public const NEVER = self::Never;
-
-
#[\Deprecated('use Type::Mixed')]
-
public const MIXED = self::Mixed;
-
-
#[\Deprecated('use Type::False')]
-
public const FALSE = self::False;
-
-
#[\Deprecated('use Type::Null')]
-
public const NULL = self::Null;
-
-
#[\Deprecated('use Type::Self')]
-
public const SELF = self::Self;
-
-
#[\Deprecated('use Type::Parent')]
-
public const PARENT = self::Parent;
-
-
#[\Deprecated('use Type::Static')]
-
public const STATIC = self::Static;
-
-
-
public static function nullable(string $type, bool $nullable = true): string
-
{
-
if (str_contains($type, '&')) {
-
return $nullable
-
? throw new Nette\InvalidArgumentException('Intersection types cannot be nullable.')
-
: $type;
-
}
-
-
$nnType = preg_replace('#^\?|^null\||\|null(?=\||$)#i', '', $type);
-
$always = (bool) preg_match('#^(null|mixed)$#i', $nnType);
-
if ($nullable) {
-
return match (true) {
-
$always, $type !== $nnType => $type,
-
str_contains($type, '|') => $type . '|null',
-
default => '?' . $type,
-
};
-
} else {
-
return $always
-
? throw new Nette\InvalidArgumentException("Type $type cannot be not nullable.")
-
: $nnType;
-
}
-
}
-
-
-
public static function union(string ...$types): string
-
{
-
return implode('|', $types);
-
}
-
-
-
public static function intersection(string ...$types): string
-
{
-
return implode('&', $types);
-
}
-
}
-21
vendor/nette/php-generator/src/PhpGenerator/Visibility.php
···
-
<?php
-
-
/**
-
* This file is part of the Nette Framework (https://nette.org)
-
* Copyright (c) 2004 David Grudl (https://davidgrudl.com)
-
*/
-
-
declare(strict_types=1);
-
-
namespace Nette\PhpGenerator;
-
-
-
/**
-
* Member visibility.
-
*/
-
enum Visibility: string
-
{
-
case Public = 'public';
-
case Protected = 'protected';
-
case Private = 'private';
-
}
+8 -1
vite.config.js
···
'index.php',
'oauth/*',
'oauth/**/*.json',
-
'lib/**/*.php',
'templates/**/*.latte',
'*.log'
]
···
},
{
src: 'pages',
+
dest: ''
+
},
+
{
+
src: 'lib',
+
dest: ''
+
},
+
{
+
src: 'data',
dest: ''
}
]